relq 1.0.97 → 1.0.98

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.
@@ -37,6 +37,15 @@ exports.introspectCockroachDB = introspectCockroachDB;
37
37
  exports.introspectTable = introspectTable;
38
38
  exports.listTables = listTables;
39
39
  exports.listSchemas = listSchemas;
40
+ function parsePgArray(val) {
41
+ if (Array.isArray(val))
42
+ return val;
43
+ if (typeof val === 'string') {
44
+ const trimmed = val.replace(/^\{|\}$/g, '');
45
+ return trimmed ? trimmed.split(',') : [];
46
+ }
47
+ return [];
48
+ }
40
49
  async function introspectCockroachDB(connection, options) {
41
50
  const { Pool } = await Promise.resolve().then(() => __importStar(require('pg')));
42
51
  const { buildPoolConfig } = await Promise.resolve().then(() => __importStar(require("../../../config/config.cjs")));
@@ -693,11 +702,15 @@ async function introspectCompositeTypes(pool) {
693
702
  GROUP BY t.oid, t.typname, n.nspname
694
703
  ORDER BY n.nspname, t.typname
695
704
  `);
696
- return result.rows.map((row) => ({
697
- name: row.name,
698
- attributes: (row.attribute_names || []).map((attrName, i) => ({
699
- name: attrName,
700
- type: row.attribute_types[i],
701
- })),
702
- }));
705
+ return result.rows.map((row) => {
706
+ const names = parsePgArray(row.attribute_names);
707
+ const types = parsePgArray(row.attribute_types);
708
+ return {
709
+ name: row.name,
710
+ attributes: names.map((attrName, i) => ({
711
+ name: attrName,
712
+ type: types[i] || 'unknown',
713
+ })),
714
+ };
715
+ });
703
716
  }
@@ -37,6 +37,15 @@ exports.introspectDsql = introspectDsql;
37
37
  exports.introspectTable = introspectTable;
38
38
  exports.listTables = listTables;
39
39
  exports.listSchemas = listSchemas;
40
+ function parsePgArray(val) {
41
+ if (Array.isArray(val))
42
+ return val;
43
+ if (typeof val === 'string') {
44
+ const trimmed = val.replace(/^\{|\}$/g, '');
45
+ return trimmed ? trimmed.split(',') : [];
46
+ }
47
+ return [];
48
+ }
40
49
  async function introspectDsql(connection, options) {
41
50
  const { Pool } = await Promise.resolve().then(() => __importStar(require('pg')));
42
51
  const { buildPoolConfig } = await Promise.resolve().then(() => __importStar(require("../../../config/config.cjs")));
@@ -681,13 +690,17 @@ async function introspectCompositeTypes(pool) {
681
690
  GROUP BY t.oid, t.typname, n.nspname
682
691
  ORDER BY n.nspname, t.typname
683
692
  `);
684
- return result.rows.map((row) => ({
685
- name: row.name,
686
- attributes: (row.attribute_names || []).map((attrName, i) => ({
687
- name: attrName,
688
- type: row.attribute_types[i],
689
- })),
690
- }));
693
+ return result.rows.map((row) => {
694
+ const names = parsePgArray(row.attribute_names);
695
+ const types = parsePgArray(row.attribute_types);
696
+ return {
697
+ name: row.name,
698
+ attributes: names.map((attrName, i) => ({
699
+ name: attrName,
700
+ type: types[i] || 'unknown',
701
+ })),
702
+ };
703
+ });
691
704
  }
692
705
  catch {
693
706
  return [];
@@ -37,6 +37,15 @@ exports.introspectNile = introspectNile;
37
37
  exports.introspectTable = introspectTable;
38
38
  exports.listTables = listTables;
39
39
  exports.listSchemas = listSchemas;
40
+ function parsePgArray(val) {
41
+ if (Array.isArray(val))
42
+ return val;
43
+ if (typeof val === 'string') {
44
+ const trimmed = val.replace(/^\{|\}$/g, '');
45
+ return trimmed ? trimmed.split(',') : [];
46
+ }
47
+ return [];
48
+ }
40
49
  async function introspectNile(connection, options) {
41
50
  const { Pool } = await Promise.resolve().then(() => __importStar(require('pg')));
42
51
  const { buildPoolConfig } = await Promise.resolve().then(() => __importStar(require("../../../config/config.cjs")));
@@ -671,11 +680,15 @@ async function introspectCompositeTypes(pool) {
671
680
  GROUP BY t.oid, t.typname, n.nspname
672
681
  ORDER BY n.nspname, t.typname
673
682
  `);
674
- return result.rows.map((row) => ({
675
- name: row.name,
676
- attributes: (row.attribute_names || []).map((attrName, i) => ({
677
- name: attrName,
678
- type: row.attribute_types[i],
679
- })),
680
- }));
683
+ return result.rows.map((row) => {
684
+ const names = parsePgArray(row.attribute_names);
685
+ const types = parsePgArray(row.attribute_types);
686
+ return {
687
+ name: row.name,
688
+ attributes: names.map((attrName, i) => ({
689
+ name: attrName,
690
+ type: types[i] || 'unknown',
691
+ })),
692
+ };
693
+ });
681
694
  }
@@ -37,6 +37,15 @@ exports.introspectPostgres = introspectPostgres;
37
37
  exports.introspectTable = introspectTable;
38
38
  exports.listTables = listTables;
39
39
  exports.listSchemas = listSchemas;
40
+ function parsePgArray(val) {
41
+ if (Array.isArray(val))
42
+ return val;
43
+ if (typeof val === 'string') {
44
+ const trimmed = val.replace(/^\{|\}$/g, '');
45
+ return trimmed ? trimmed.split(',') : [];
46
+ }
47
+ return [];
48
+ }
40
49
  async function introspectPostgres(connection, options) {
41
50
  const { Pool } = await Promise.resolve().then(() => __importStar(require('pg')));
42
51
  const { buildPoolConfig } = await Promise.resolve().then(() => __importStar(require("../../../config/config.cjs")));
@@ -675,11 +684,15 @@ async function introspectCompositeTypes(pool) {
675
684
  GROUP BY t.oid, t.typname, n.nspname
676
685
  ORDER BY n.nspname, t.typname
677
686
  `);
678
- return result.rows.map((row) => ({
679
- name: row.name,
680
- attributes: (row.attribute_names || []).map((attrName, i) => ({
681
- name: attrName,
682
- type: row.attribute_types[i],
683
- })),
684
- }));
687
+ return result.rows.map((row) => {
688
+ const names = parsePgArray(row.attribute_names);
689
+ const types = parsePgArray(row.attribute_types);
690
+ return {
691
+ name: row.name,
692
+ attributes: names.map((attrName, i) => ({
693
+ name: attrName,
694
+ type: types[i] || 'unknown',
695
+ })),
696
+ };
697
+ });
685
698
  }
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ensureCertificates = ensureCertificates;
4
+ exports.checkCertificates = checkCertificates;
5
+ exports.getMkcertCaRoot = getMkcertCaRoot;
6
+ exports.isMkcertInstalled = isMkcertInstalled;
7
+ exports.getMkcertInstallInstructions = getMkcertInstallInstructions;
8
+ const node_child_process_1 = require("node:child_process");
9
+ const promises_1 = require("node:fs/promises");
10
+ const node_path_1 = require("node:path");
11
+ const node_os_1 = require("node:os");
12
+ const DOMAIN = "local.relq.studio";
13
+ const CERTS_DIR = (0, node_path_1.join)((0, node_os_1.homedir)(), ".relq", "certs");
14
+ const KEY_FILE = `${DOMAIN}-key.pem`;
15
+ const CERT_FILE = `${DOMAIN}.pem`;
16
+ async function ensureCertificates() {
17
+ const keyPath = (0, node_path_1.join)(CERTS_DIR, KEY_FILE);
18
+ const certPath = (0, node_path_1.join)(CERTS_DIR, CERT_FILE);
19
+ const status = await checkCertificates();
20
+ if (status.exists && !status.expired) {
21
+ return { key: keyPath, cert: certPath };
22
+ }
23
+ assertMkcertInstalled();
24
+ await (0, promises_1.mkdir)(CERTS_DIR, { recursive: true });
25
+ (0, node_child_process_1.execSync)(`mkcert -key-file "${keyPath}" -cert-file "${certPath}" ${DOMAIN}`, { cwd: CERTS_DIR, stdio: "pipe" });
26
+ return { key: keyPath, cert: certPath };
27
+ }
28
+ async function checkCertificates() {
29
+ const keyPath = (0, node_path_1.join)(CERTS_DIR, KEY_FILE);
30
+ const certPath = (0, node_path_1.join)(CERTS_DIR, CERT_FILE);
31
+ try {
32
+ await (0, promises_1.access)(keyPath);
33
+ await (0, promises_1.access)(certPath);
34
+ }
35
+ catch {
36
+ return { exists: false, expired: false };
37
+ }
38
+ try {
39
+ const certContent = await (0, promises_1.readFile)(certPath, "utf-8");
40
+ const expiresAt = parseCertificateExpiry(certContent);
41
+ if (expiresAt && expiresAt.getTime() < Date.now()) {
42
+ return { exists: true, expired: true, expiresAt };
43
+ }
44
+ return {
45
+ exists: true,
46
+ expired: false,
47
+ paths: { key: keyPath, cert: certPath },
48
+ expiresAt: expiresAt ?? undefined,
49
+ };
50
+ }
51
+ catch {
52
+ return { exists: true, expired: true };
53
+ }
54
+ }
55
+ function getMkcertCaRoot() {
56
+ try {
57
+ const output = (0, node_child_process_1.execSync)("mkcert -CAROOT", { encoding: "utf-8" });
58
+ return output.trim();
59
+ }
60
+ catch {
61
+ return null;
62
+ }
63
+ }
64
+ function isMkcertInstalled() {
65
+ try {
66
+ (0, node_child_process_1.execSync)("mkcert -version", { stdio: "ignore" });
67
+ return true;
68
+ }
69
+ catch {
70
+ return false;
71
+ }
72
+ }
73
+ function getMkcertInstallInstructions() {
74
+ return [
75
+ "mkcert is required for local HTTPS.",
76
+ "",
77
+ "Install mkcert:",
78
+ " macOS: brew install mkcert nss",
79
+ " Linux: sudo apt install mkcert",
80
+ " Windows: choco install mkcert",
81
+ "",
82
+ "Then install the local CA:",
83
+ " mkcert -install",
84
+ ].join("\n");
85
+ }
86
+ function assertMkcertInstalled() {
87
+ if (!isMkcertInstalled()) {
88
+ throw new Error(getMkcertInstallInstructions());
89
+ }
90
+ }
91
+ function parseCertificateExpiry(pemContent) {
92
+ try {
93
+ const { X509Certificate } = require("node:crypto");
94
+ const cert = new X509Certificate(pemContent);
95
+ return new Date(cert.validTo);
96
+ }
97
+ catch {
98
+ return null;
99
+ }
100
+ }
@@ -35,6 +35,15 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.introspectCockroachDB = introspectCockroachDB;
37
37
  const config_1 = require("../../../config/config.cjs");
38
+ function parsePgArray(val) {
39
+ if (Array.isArray(val))
40
+ return val;
41
+ if (typeof val === 'string') {
42
+ const trimmed = val.replace(/^\{|\}$/g, '');
43
+ return trimmed ? trimmed.split(',') : [];
44
+ }
45
+ return [];
46
+ }
38
47
  function mapInternalType(internalType) {
39
48
  const typeMap = {
40
49
  'int2': 'smallint',
@@ -319,13 +328,17 @@ async function introspectCockroachDB(connection, options) {
319
328
  ORDER BY n.nspname, t.typname
320
329
  `);
321
330
  onDetailedProgress?.({ step: 'composite_types', count: compositeTypesResult.rows.length, status: 'done' });
322
- const compositeTypes = compositeTypesResult.rows.map(row => ({
323
- name: row.name,
324
- attributes: (row.attribute_names || []).map((attrName, i) => ({
325
- name: attrName,
326
- type: row.attribute_types[i],
327
- })),
328
- }));
331
+ const compositeTypes = compositeTypesResult.rows.map(row => {
332
+ const names = parsePgArray(row.attribute_names);
333
+ const types = parsePgArray(row.attribute_types);
334
+ return {
335
+ name: row.name,
336
+ attributes: names.map((attrName, i) => ({
337
+ name: attrName,
338
+ type: types[i] || 'unknown',
339
+ })),
340
+ };
341
+ });
329
342
  onProgress?.('processing');
330
343
  const columnsByTable = new Map();
331
344
  const constraintsByTable = new Map();
@@ -35,6 +35,15 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.introspectDsql = introspectDsql;
37
37
  const config_1 = require("../../../config/config.cjs");
38
+ function parsePgArray(val) {
39
+ if (Array.isArray(val))
40
+ return val;
41
+ if (typeof val === 'string') {
42
+ const trimmed = val.replace(/^\{|\}$/g, '');
43
+ return trimmed ? trimmed.split(',') : [];
44
+ }
45
+ return [];
46
+ }
38
47
  function mapInternalType(internalType) {
39
48
  const typeMap = {
40
49
  'int2': 'smallint',
@@ -306,13 +315,17 @@ async function introspectDsql(connection, options) {
306
315
  GROUP BY t.oid, t.typname, n.nspname
307
316
  ORDER BY n.nspname, t.typname
308
317
  `);
309
- compositeTypes = compositeTypesResult.rows.map(row => ({
310
- name: row.name,
311
- attributes: (row.attribute_names || []).map((attrName, i) => ({
312
- name: attrName,
313
- type: row.attribute_types[i],
314
- })),
315
- }));
318
+ compositeTypes = compositeTypesResult.rows.map(row => {
319
+ const names = parsePgArray(row.attribute_names);
320
+ const types = parsePgArray(row.attribute_types);
321
+ return {
322
+ name: row.name,
323
+ attributes: names.map((attrName, i) => ({
324
+ name: attrName,
325
+ type: types[i] || 'unknown',
326
+ })),
327
+ };
328
+ });
316
329
  }
317
330
  catch {
318
331
  }
@@ -35,6 +35,15 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.introspectNile = introspectNile;
37
37
  const config_1 = require("../../../config/config.cjs");
38
+ function parsePgArray(val) {
39
+ if (Array.isArray(val))
40
+ return val;
41
+ if (typeof val === 'string') {
42
+ const trimmed = val.replace(/^\{|\}$/g, '');
43
+ return trimmed ? trimmed.split(',') : [];
44
+ }
45
+ return [];
46
+ }
38
47
  const NILE_SYSTEM_TABLES = ['tenants', 'tenant_users'];
39
48
  const NILE_SYSTEM_SCHEMAS = ['nile', 'pg_catalog', 'information_schema', 'pg_toast'];
40
49
  function parseOptionsArray(options) {
@@ -335,13 +344,17 @@ async function introspectNile(connection, options) {
335
344
  ORDER BY n.nspname, t.typname
336
345
  `);
337
346
  onDetailedProgress?.({ step: 'composite_types', count: compositeTypesResult.rows.length, status: 'done' });
338
- const compositeTypes = compositeTypesResult.rows.map(row => ({
339
- name: row.name,
340
- attributes: (row.attribute_names || []).map((attrName, i) => ({
341
- name: attrName,
342
- type: row.attribute_types[i],
343
- })),
344
- }));
347
+ const compositeTypes = compositeTypesResult.rows.map(row => {
348
+ const names = parsePgArray(row.attribute_names);
349
+ const types = parsePgArray(row.attribute_types);
350
+ return {
351
+ name: row.name,
352
+ attributes: names.map((attrName, i) => ({
353
+ name: attrName,
354
+ type: types[i] || 'unknown',
355
+ })),
356
+ };
357
+ });
345
358
  onProgress?.('processing');
346
359
  const columnsByTable = new Map();
347
360
  const constraintsByTable = new Map();
@@ -35,6 +35,15 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.introspectPostgres = introspectPostgres;
37
37
  const config_1 = require("../../../config/config.cjs");
38
+ function parsePgArray(val) {
39
+ if (Array.isArray(val))
40
+ return val;
41
+ if (typeof val === 'string') {
42
+ const trimmed = val.replace(/^\{|\}$/g, '');
43
+ return trimmed ? trimmed.split(',') : [];
44
+ }
45
+ return [];
46
+ }
38
47
  function parseOptionsArray(options) {
39
48
  if (!options)
40
49
  return {};
@@ -328,13 +337,17 @@ async function introspectPostgres(connection, options) {
328
337
  ORDER BY n.nspname, t.typname
329
338
  `);
330
339
  onDetailedProgress?.({ step: 'composite_types', count: compositeTypesResult.rows.length, status: 'done' });
331
- const compositeTypes = compositeTypesResult.rows.map(row => ({
332
- name: row.name,
333
- attributes: (row.attribute_names || []).map((attrName, i) => ({
334
- name: attrName,
335
- type: row.attribute_types[i],
336
- })),
337
- }));
340
+ const compositeTypes = compositeTypesResult.rows.map(row => {
341
+ const names = parsePgArray(row.attribute_names);
342
+ const types = parsePgArray(row.attribute_types);
343
+ return {
344
+ name: row.name,
345
+ attributes: names.map((attrName, i) => ({
346
+ name: attrName,
347
+ type: types[i] || 'unknown',
348
+ })),
349
+ };
350
+ });
338
351
  onProgress?.('processing');
339
352
  const columnsByTable = new Map();
340
353
  const constraintsByTable = new Map();
@@ -1,3 +1,12 @@
1
+ function parsePgArray(val) {
2
+ if (Array.isArray(val))
3
+ return val;
4
+ if (typeof val === 'string') {
5
+ const trimmed = val.replace(/^\{|\}$/g, '');
6
+ return trimmed ? trimmed.split(',') : [];
7
+ }
8
+ return [];
9
+ }
1
10
  export async function introspectCockroachDB(connection, options) {
2
11
  const { Pool } = await import('pg');
3
12
  const { buildPoolConfig } = await import("../../../config/config.js");
@@ -654,11 +663,15 @@ async function introspectCompositeTypes(pool) {
654
663
  GROUP BY t.oid, t.typname, n.nspname
655
664
  ORDER BY n.nspname, t.typname
656
665
  `);
657
- return result.rows.map((row) => ({
658
- name: row.name,
659
- attributes: (row.attribute_names || []).map((attrName, i) => ({
660
- name: attrName,
661
- type: row.attribute_types[i],
662
- })),
663
- }));
666
+ return result.rows.map((row) => {
667
+ const names = parsePgArray(row.attribute_names);
668
+ const types = parsePgArray(row.attribute_types);
669
+ return {
670
+ name: row.name,
671
+ attributes: names.map((attrName, i) => ({
672
+ name: attrName,
673
+ type: types[i] || 'unknown',
674
+ })),
675
+ };
676
+ });
664
677
  }
@@ -1,3 +1,12 @@
1
+ function parsePgArray(val) {
2
+ if (Array.isArray(val))
3
+ return val;
4
+ if (typeof val === 'string') {
5
+ const trimmed = val.replace(/^\{|\}$/g, '');
6
+ return trimmed ? trimmed.split(',') : [];
7
+ }
8
+ return [];
9
+ }
1
10
  export async function introspectDsql(connection, options) {
2
11
  const { Pool } = await import('pg');
3
12
  const { buildPoolConfig } = await import("../../../config/config.js");
@@ -642,13 +651,17 @@ async function introspectCompositeTypes(pool) {
642
651
  GROUP BY t.oid, t.typname, n.nspname
643
652
  ORDER BY n.nspname, t.typname
644
653
  `);
645
- return result.rows.map((row) => ({
646
- name: row.name,
647
- attributes: (row.attribute_names || []).map((attrName, i) => ({
648
- name: attrName,
649
- type: row.attribute_types[i],
650
- })),
651
- }));
654
+ return result.rows.map((row) => {
655
+ const names = parsePgArray(row.attribute_names);
656
+ const types = parsePgArray(row.attribute_types);
657
+ return {
658
+ name: row.name,
659
+ attributes: names.map((attrName, i) => ({
660
+ name: attrName,
661
+ type: types[i] || 'unknown',
662
+ })),
663
+ };
664
+ });
652
665
  }
653
666
  catch {
654
667
  return [];
@@ -1,3 +1,12 @@
1
+ function parsePgArray(val) {
2
+ if (Array.isArray(val))
3
+ return val;
4
+ if (typeof val === 'string') {
5
+ const trimmed = val.replace(/^\{|\}$/g, '');
6
+ return trimmed ? trimmed.split(',') : [];
7
+ }
8
+ return [];
9
+ }
1
10
  export async function introspectNile(connection, options) {
2
11
  const { Pool } = await import('pg');
3
12
  const { buildPoolConfig } = await import("../../../config/config.js");
@@ -632,11 +641,15 @@ async function introspectCompositeTypes(pool) {
632
641
  GROUP BY t.oid, t.typname, n.nspname
633
642
  ORDER BY n.nspname, t.typname
634
643
  `);
635
- return result.rows.map((row) => ({
636
- name: row.name,
637
- attributes: (row.attribute_names || []).map((attrName, i) => ({
638
- name: attrName,
639
- type: row.attribute_types[i],
640
- })),
641
- }));
644
+ return result.rows.map((row) => {
645
+ const names = parsePgArray(row.attribute_names);
646
+ const types = parsePgArray(row.attribute_types);
647
+ return {
648
+ name: row.name,
649
+ attributes: names.map((attrName, i) => ({
650
+ name: attrName,
651
+ type: types[i] || 'unknown',
652
+ })),
653
+ };
654
+ });
642
655
  }
@@ -1,3 +1,12 @@
1
+ function parsePgArray(val) {
2
+ if (Array.isArray(val))
3
+ return val;
4
+ if (typeof val === 'string') {
5
+ const trimmed = val.replace(/^\{|\}$/g, '');
6
+ return trimmed ? trimmed.split(',') : [];
7
+ }
8
+ return [];
9
+ }
1
10
  export async function introspectPostgres(connection, options) {
2
11
  const { Pool } = await import('pg');
3
12
  const { buildPoolConfig } = await import("../../../config/config.js");
@@ -636,11 +645,15 @@ async function introspectCompositeTypes(pool) {
636
645
  GROUP BY t.oid, t.typname, n.nspname
637
646
  ORDER BY n.nspname, t.typname
638
647
  `);
639
- return result.rows.map((row) => ({
640
- name: row.name,
641
- attributes: (row.attribute_names || []).map((attrName, i) => ({
642
- name: attrName,
643
- type: row.attribute_types[i],
644
- })),
645
- }));
648
+ return result.rows.map((row) => {
649
+ const names = parsePgArray(row.attribute_names);
650
+ const types = parsePgArray(row.attribute_types);
651
+ return {
652
+ name: row.name,
653
+ attributes: names.map((attrName, i) => ({
654
+ name: attrName,
655
+ type: types[i] || 'unknown',
656
+ })),
657
+ };
658
+ });
646
659
  }
@@ -0,0 +1,93 @@
1
+ import { execSync } from "node:child_process";
2
+ import { access, mkdir, readFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { homedir } from "node:os";
5
+ const DOMAIN = "local.relq.studio";
6
+ const CERTS_DIR = join(homedir(), ".relq", "certs");
7
+ const KEY_FILE = `${DOMAIN}-key.pem`;
8
+ const CERT_FILE = `${DOMAIN}.pem`;
9
+ export async function ensureCertificates() {
10
+ const keyPath = join(CERTS_DIR, KEY_FILE);
11
+ const certPath = join(CERTS_DIR, CERT_FILE);
12
+ const status = await checkCertificates();
13
+ if (status.exists && !status.expired) {
14
+ return { key: keyPath, cert: certPath };
15
+ }
16
+ assertMkcertInstalled();
17
+ await mkdir(CERTS_DIR, { recursive: true });
18
+ execSync(`mkcert -key-file "${keyPath}" -cert-file "${certPath}" ${DOMAIN}`, { cwd: CERTS_DIR, stdio: "pipe" });
19
+ return { key: keyPath, cert: certPath };
20
+ }
21
+ export async function checkCertificates() {
22
+ const keyPath = join(CERTS_DIR, KEY_FILE);
23
+ const certPath = join(CERTS_DIR, CERT_FILE);
24
+ try {
25
+ await access(keyPath);
26
+ await access(certPath);
27
+ }
28
+ catch {
29
+ return { exists: false, expired: false };
30
+ }
31
+ try {
32
+ const certContent = await readFile(certPath, "utf-8");
33
+ const expiresAt = parseCertificateExpiry(certContent);
34
+ if (expiresAt && expiresAt.getTime() < Date.now()) {
35
+ return { exists: true, expired: true, expiresAt };
36
+ }
37
+ return {
38
+ exists: true,
39
+ expired: false,
40
+ paths: { key: keyPath, cert: certPath },
41
+ expiresAt: expiresAt ?? undefined,
42
+ };
43
+ }
44
+ catch {
45
+ return { exists: true, expired: true };
46
+ }
47
+ }
48
+ export function getMkcertCaRoot() {
49
+ try {
50
+ const output = execSync("mkcert -CAROOT", { encoding: "utf-8" });
51
+ return output.trim();
52
+ }
53
+ catch {
54
+ return null;
55
+ }
56
+ }
57
+ export function isMkcertInstalled() {
58
+ try {
59
+ execSync("mkcert -version", { stdio: "ignore" });
60
+ return true;
61
+ }
62
+ catch {
63
+ return false;
64
+ }
65
+ }
66
+ export function getMkcertInstallInstructions() {
67
+ return [
68
+ "mkcert is required for local HTTPS.",
69
+ "",
70
+ "Install mkcert:",
71
+ " macOS: brew install mkcert nss",
72
+ " Linux: sudo apt install mkcert",
73
+ " Windows: choco install mkcert",
74
+ "",
75
+ "Then install the local CA:",
76
+ " mkcert -install",
77
+ ].join("\n");
78
+ }
79
+ function assertMkcertInstalled() {
80
+ if (!isMkcertInstalled()) {
81
+ throw new Error(getMkcertInstallInstructions());
82
+ }
83
+ }
84
+ function parseCertificateExpiry(pemContent) {
85
+ try {
86
+ const { X509Certificate } = require("node:crypto");
87
+ const cert = new X509Certificate(pemContent);
88
+ return new Date(cert.validTo);
89
+ }
90
+ catch {
91
+ return null;
92
+ }
93
+ }
@@ -1,4 +1,13 @@
1
1
  import { buildPoolConfig } from "../../../config/config.js";
2
+ function parsePgArray(val) {
3
+ if (Array.isArray(val))
4
+ return val;
5
+ if (typeof val === 'string') {
6
+ const trimmed = val.replace(/^\{|\}$/g, '');
7
+ return trimmed ? trimmed.split(',') : [];
8
+ }
9
+ return [];
10
+ }
2
11
  function mapInternalType(internalType) {
3
12
  const typeMap = {
4
13
  'int2': 'smallint',
@@ -283,13 +292,17 @@ export async function introspectCockroachDB(connection, options) {
283
292
  ORDER BY n.nspname, t.typname
284
293
  `);
285
294
  onDetailedProgress?.({ step: 'composite_types', count: compositeTypesResult.rows.length, status: 'done' });
286
- const compositeTypes = compositeTypesResult.rows.map(row => ({
287
- name: row.name,
288
- attributes: (row.attribute_names || []).map((attrName, i) => ({
289
- name: attrName,
290
- type: row.attribute_types[i],
291
- })),
292
- }));
295
+ const compositeTypes = compositeTypesResult.rows.map(row => {
296
+ const names = parsePgArray(row.attribute_names);
297
+ const types = parsePgArray(row.attribute_types);
298
+ return {
299
+ name: row.name,
300
+ attributes: names.map((attrName, i) => ({
301
+ name: attrName,
302
+ type: types[i] || 'unknown',
303
+ })),
304
+ };
305
+ });
293
306
  onProgress?.('processing');
294
307
  const columnsByTable = new Map();
295
308
  const constraintsByTable = new Map();
@@ -1,4 +1,13 @@
1
1
  import { buildPoolConfig } from "../../../config/config.js";
2
+ function parsePgArray(val) {
3
+ if (Array.isArray(val))
4
+ return val;
5
+ if (typeof val === 'string') {
6
+ const trimmed = val.replace(/^\{|\}$/g, '');
7
+ return trimmed ? trimmed.split(',') : [];
8
+ }
9
+ return [];
10
+ }
2
11
  function mapInternalType(internalType) {
3
12
  const typeMap = {
4
13
  'int2': 'smallint',
@@ -270,13 +279,17 @@ export async function introspectDsql(connection, options) {
270
279
  GROUP BY t.oid, t.typname, n.nspname
271
280
  ORDER BY n.nspname, t.typname
272
281
  `);
273
- compositeTypes = compositeTypesResult.rows.map(row => ({
274
- name: row.name,
275
- attributes: (row.attribute_names || []).map((attrName, i) => ({
276
- name: attrName,
277
- type: row.attribute_types[i],
278
- })),
279
- }));
282
+ compositeTypes = compositeTypesResult.rows.map(row => {
283
+ const names = parsePgArray(row.attribute_names);
284
+ const types = parsePgArray(row.attribute_types);
285
+ return {
286
+ name: row.name,
287
+ attributes: names.map((attrName, i) => ({
288
+ name: attrName,
289
+ type: types[i] || 'unknown',
290
+ })),
291
+ };
292
+ });
280
293
  }
281
294
  catch {
282
295
  }
@@ -1,4 +1,13 @@
1
1
  import { buildPoolConfig } from "../../../config/config.js";
2
+ function parsePgArray(val) {
3
+ if (Array.isArray(val))
4
+ return val;
5
+ if (typeof val === 'string') {
6
+ const trimmed = val.replace(/^\{|\}$/g, '');
7
+ return trimmed ? trimmed.split(',') : [];
8
+ }
9
+ return [];
10
+ }
2
11
  const NILE_SYSTEM_TABLES = ['tenants', 'tenant_users'];
3
12
  const NILE_SYSTEM_SCHEMAS = ['nile', 'pg_catalog', 'information_schema', 'pg_toast'];
4
13
  function parseOptionsArray(options) {
@@ -299,13 +308,17 @@ export async function introspectNile(connection, options) {
299
308
  ORDER BY n.nspname, t.typname
300
309
  `);
301
310
  onDetailedProgress?.({ step: 'composite_types', count: compositeTypesResult.rows.length, status: 'done' });
302
- const compositeTypes = compositeTypesResult.rows.map(row => ({
303
- name: row.name,
304
- attributes: (row.attribute_names || []).map((attrName, i) => ({
305
- name: attrName,
306
- type: row.attribute_types[i],
307
- })),
308
- }));
311
+ const compositeTypes = compositeTypesResult.rows.map(row => {
312
+ const names = parsePgArray(row.attribute_names);
313
+ const types = parsePgArray(row.attribute_types);
314
+ return {
315
+ name: row.name,
316
+ attributes: names.map((attrName, i) => ({
317
+ name: attrName,
318
+ type: types[i] || 'unknown',
319
+ })),
320
+ };
321
+ });
309
322
  onProgress?.('processing');
310
323
  const columnsByTable = new Map();
311
324
  const constraintsByTable = new Map();
@@ -1,4 +1,13 @@
1
1
  import { buildPoolConfig } from "../../../config/config.js";
2
+ function parsePgArray(val) {
3
+ if (Array.isArray(val))
4
+ return val;
5
+ if (typeof val === 'string') {
6
+ const trimmed = val.replace(/^\{|\}$/g, '');
7
+ return trimmed ? trimmed.split(',') : [];
8
+ }
9
+ return [];
10
+ }
2
11
  function parseOptionsArray(options) {
3
12
  if (!options)
4
13
  return {};
@@ -292,13 +301,17 @@ export async function introspectPostgres(connection, options) {
292
301
  ORDER BY n.nspname, t.typname
293
302
  `);
294
303
  onDetailedProgress?.({ step: 'composite_types', count: compositeTypesResult.rows.length, status: 'done' });
295
- const compositeTypes = compositeTypesResult.rows.map(row => ({
296
- name: row.name,
297
- attributes: (row.attribute_names || []).map((attrName, i) => ({
298
- name: attrName,
299
- type: row.attribute_types[i],
300
- })),
301
- }));
304
+ const compositeTypes = compositeTypesResult.rows.map(row => {
305
+ const names = parsePgArray(row.attribute_names);
306
+ const types = parsePgArray(row.attribute_types);
307
+ return {
308
+ name: row.name,
309
+ attributes: names.map((attrName, i) => ({
310
+ name: attrName,
311
+ type: types[i] || 'unknown',
312
+ })),
313
+ };
314
+ });
302
315
  onProgress?.('processing');
303
316
  const columnsByTable = new Map();
304
317
  const constraintsByTable = new Map();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relq",
3
- "version": "1.0.97",
3
+ "version": "1.0.98",
4
4
  "description": "The Fully-Typed PostgreSQL ORM for TypeScript",
5
5
  "author": "Olajide Mathew O. <olajide.mathew@yuniq.solutions>",
6
6
  "license": "MIT",