@eclesia/indexer-engine 2.9.9 → 2.10.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants.cjs +74 -0
- package/dist/constants.cjs.map +1 -0
- package/dist/constants.d.cts +68 -0
- package/dist/constants.d.cts.map +1 -0
- package/dist/constants.d.ts +68 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +64 -0
- package/dist/constants.js.map +1 -0
- package/dist/emitter/index.cjs +0 -1
- package/dist/emitter/index.cjs.map +1 -1
- package/dist/errors/index.cjs +107 -0
- package/dist/errors/index.cjs.map +1 -0
- package/dist/errors/index.d.cts +75 -0
- package/dist/errors/index.d.cts.map +1 -0
- package/dist/errors/index.d.ts +75 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +100 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.cjs +38 -10
- package/dist/index.d.cts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +5 -1
- package/dist/indexer/index.cjs +51 -27
- package/dist/indexer/index.cjs.map +1 -1
- package/dist/indexer/index.d.cts +1 -0
- package/dist/indexer/index.d.cts.map +1 -1
- package/dist/indexer/index.d.ts +1 -0
- package/dist/indexer/index.d.ts.map +1 -1
- package/dist/indexer/index.js +51 -20
- package/dist/indexer/index.js.map +1 -1
- package/dist/metrics/index.cjs +146 -0
- package/dist/metrics/index.cjs.map +1 -0
- package/dist/metrics/index.d.cts +56 -0
- package/dist/metrics/index.d.cts.map +1 -0
- package/dist/metrics/index.d.ts +56 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/metrics/index.js +145 -0
- package/dist/metrics/index.js.map +1 -0
- package/dist/promise-queue/index.cjs +6 -4
- package/dist/promise-queue/index.cjs.map +1 -1
- package/dist/promise-queue/index.d.cts +6 -2
- package/dist/promise-queue/index.d.cts.map +1 -1
- package/dist/promise-queue/index.d.ts +6 -2
- package/dist/promise-queue/index.d.ts.map +1 -1
- package/dist/promise-queue/index.js +6 -4
- package/dist/promise-queue/index.js.map +1 -1
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.cts +6 -0
- package/dist/types/index.d.cts.map +1 -1
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/bech32.cjs +0 -1
- package/dist/utils/bech32.cjs.map +1 -1
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/validation/index.cjs +150 -0
- package/dist/validation/index.cjs.map +1 -0
- package/dist/validation/index.d.cts +52 -0
- package/dist/validation/index.d.cts.map +1 -0
- package/dist/validation/index.d.ts +52 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +140 -0
- package/dist/validation/index.js.map +1 -0
- package/package.json +3 -1
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_index = require('../errors/index.cjs');
|
|
3
|
+
let fs = require("fs");
|
|
4
|
+
fs = require_rolldown_runtime.__toESM(fs);
|
|
5
|
+
|
|
6
|
+
//#region src/validation/index.ts
|
|
7
|
+
/**
|
|
8
|
+
* Configuration validation utilities for the Eclesia indexer
|
|
9
|
+
* Validates configuration parameters before initialization
|
|
10
|
+
*/
|
|
11
|
+
var validation_exports = /* @__PURE__ */ require_rolldown_runtime.__export({
|
|
12
|
+
getChainPrefix: () => getChainPrefix,
|
|
13
|
+
validateFilePath: () => validateFilePath,
|
|
14
|
+
validatePort: () => validatePort,
|
|
15
|
+
validatePositiveInteger: () => validatePositiveInteger,
|
|
16
|
+
validatePostgresConnectionString: () => validatePostgresConnectionString,
|
|
17
|
+
validateUrl: () => validateUrl
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* Validates a URL string
|
|
21
|
+
* @param url - The URL to validate
|
|
22
|
+
* @param fieldName - Name of the field for error messages
|
|
23
|
+
* @throws {ConfigurationError} If URL is invalid
|
|
24
|
+
*/
|
|
25
|
+
function validateUrl(url, fieldName = "URL") {
|
|
26
|
+
if (!url || typeof url !== "string") throw new require_index.ConfigurationError(`${fieldName} is required and must be a string`, {
|
|
27
|
+
fieldName,
|
|
28
|
+
value: url
|
|
29
|
+
});
|
|
30
|
+
try {
|
|
31
|
+
const parsed = new URL(url);
|
|
32
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:" && parsed.protocol !== "ws:" && parsed.protocol !== "wss:") throw new require_index.ConfigurationError(`${fieldName} must use http, https, ws, or wss protocol`, {
|
|
33
|
+
fieldName,
|
|
34
|
+
url,
|
|
35
|
+
protocol: parsed.protocol
|
|
36
|
+
});
|
|
37
|
+
if (!parsed.hostname) throw new require_index.ConfigurationError(`${fieldName} must include a hostname`, {
|
|
38
|
+
fieldName,
|
|
39
|
+
url
|
|
40
|
+
});
|
|
41
|
+
} catch (error) {
|
|
42
|
+
if (error instanceof require_index.ConfigurationError) throw error;
|
|
43
|
+
throw new require_index.ConfigurationError(`${fieldName} is not a valid URL: ${error}`, {
|
|
44
|
+
fieldName,
|
|
45
|
+
url
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Validates a file path exists and is readable
|
|
51
|
+
* @param filePath - The file path to validate
|
|
52
|
+
* @param fieldName - Name of the field for error messages
|
|
53
|
+
* @throws {ConfigurationError} If file doesn't exist or isn't readable
|
|
54
|
+
*/
|
|
55
|
+
function validateFilePath(filePath, fieldName = "File path") {
|
|
56
|
+
if (!filePath || typeof filePath !== "string") throw new require_index.ConfigurationError(`${fieldName} is required and must be a string`, {
|
|
57
|
+
fieldName,
|
|
58
|
+
value: filePath
|
|
59
|
+
});
|
|
60
|
+
if (!fs.existsSync(filePath)) throw new require_index.ConfigurationError(`${fieldName} does not exist: ${filePath}`, {
|
|
61
|
+
fieldName,
|
|
62
|
+
filePath
|
|
63
|
+
});
|
|
64
|
+
try {
|
|
65
|
+
fs.accessSync(filePath, fs.constants.R_OK);
|
|
66
|
+
} catch (error) {
|
|
67
|
+
throw new require_index.ConfigurationError(`${fieldName} is not readable: ${filePath}`, {
|
|
68
|
+
fieldName,
|
|
69
|
+
filePath,
|
|
70
|
+
error: String(error)
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Validates a PostgreSQL connection string
|
|
76
|
+
* @param connectionString - The connection string to validate
|
|
77
|
+
* @param fieldName - Name of the field for error messages
|
|
78
|
+
* @throws {ConfigurationError} If connection string is invalid
|
|
79
|
+
*/
|
|
80
|
+
function validatePostgresConnectionString(connectionString, fieldName = "Database connection string") {
|
|
81
|
+
if (!connectionString || typeof connectionString !== "string") throw new require_index.ConfigurationError(`${fieldName} is required and must be a string`, {
|
|
82
|
+
fieldName,
|
|
83
|
+
value: connectionString
|
|
84
|
+
});
|
|
85
|
+
if (!/^postgres(?:ql)?:\/\/(?:([^:]+)(?::([^@]+))?@)?([^:/]+)(?::(\d+))?\/(.+)$/.test(connectionString)) throw new require_index.ConfigurationError(`${fieldName} must be in format: postgres://user:password@host:port/database`, {
|
|
86
|
+
fieldName,
|
|
87
|
+
format: "postgres://user:password@host:port/database"
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Validates a port number
|
|
92
|
+
* @param port - The port number to validate
|
|
93
|
+
* @param fieldName - Name of the field for error messages
|
|
94
|
+
* @throws {ConfigurationError} If port is invalid
|
|
95
|
+
*/
|
|
96
|
+
function validatePort(port, fieldName = "Port") {
|
|
97
|
+
if (typeof port !== "number" || !Number.isInteger(port)) throw new require_index.ConfigurationError(`${fieldName} must be an integer`, {
|
|
98
|
+
fieldName,
|
|
99
|
+
value: port
|
|
100
|
+
});
|
|
101
|
+
if (port < 1 || port > 65535) throw new require_index.ConfigurationError(`${fieldName} must be between 1 and 65535`, {
|
|
102
|
+
fieldName,
|
|
103
|
+
value: port,
|
|
104
|
+
min: 1,
|
|
105
|
+
max: 65535
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Validates a positive integer
|
|
110
|
+
* @param value - The value to validate
|
|
111
|
+
* @param fieldName - Name of the field for error messages
|
|
112
|
+
* @throws {ConfigurationError} If value is not a positive integer
|
|
113
|
+
*/
|
|
114
|
+
function validatePositiveInteger(value, fieldName = "Value") {
|
|
115
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) throw new require_index.ConfigurationError(`${fieldName} must be a positive integer`, {
|
|
116
|
+
fieldName,
|
|
117
|
+
value
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Gets and validates the chain prefix from environment variables
|
|
122
|
+
* @param defaultPrefix - Default prefix to use if environment variable is not set
|
|
123
|
+
* @returns The validated chain prefix
|
|
124
|
+
* @throws {ConfigurationError} If chain prefix is invalid
|
|
125
|
+
*/
|
|
126
|
+
function getChainPrefix(defaultPrefix = "cosmos") {
|
|
127
|
+
const prefix = process.env.CHAIN_PREFIX ?? defaultPrefix;
|
|
128
|
+
if (!prefix || typeof prefix !== "string") throw new require_index.ConfigurationError("CHAIN_PREFIX must be a non-empty string", {
|
|
129
|
+
value: prefix,
|
|
130
|
+
defaultPrefix
|
|
131
|
+
});
|
|
132
|
+
if (!/^[a-z][a-z0-9]*$/.test(prefix)) throw new require_index.ConfigurationError("CHAIN_PREFIX must start with lowercase letter and contain only lowercase letters and numbers", {
|
|
133
|
+
value: prefix,
|
|
134
|
+
pattern: "^[a-z][a-z0-9]*$"
|
|
135
|
+
});
|
|
136
|
+
return prefix;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
//#endregion
|
|
140
|
+
exports.validateFilePath = validateFilePath;
|
|
141
|
+
exports.validatePort = validatePort;
|
|
142
|
+
exports.validatePositiveInteger = validatePositiveInteger;
|
|
143
|
+
exports.validateUrl = validateUrl;
|
|
144
|
+
Object.defineProperty(exports, 'validation_exports', {
|
|
145
|
+
enumerable: true,
|
|
146
|
+
get: function () {
|
|
147
|
+
return validation_exports;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["ConfigurationError"],"sources":["../../src/validation/index.ts"],"sourcesContent":["/**\n * Configuration validation utilities for the Eclesia indexer\n * Validates configuration parameters before initialization\n */\n\nimport * as fs from \"node:fs\";\n\nimport {\n ConfigurationError,\n} from \"../errors/index.js\";\n\n/**\n * Validates a URL string\n * @param url - The URL to validate\n * @param fieldName - Name of the field for error messages\n * @throws {ConfigurationError} If URL is invalid\n */\nexport function validateUrl(url: string, fieldName: string = \"URL\"): void {\n if (!url || typeof url !== \"string\") {\n throw new ConfigurationError(`${fieldName} is required and must be a string`, {\n fieldName,\n value: url,\n });\n }\n\n try {\n const parsed = new URL(url);\n\n // Ensure protocol is http or https\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\" && parsed.protocol !== \"ws:\" && parsed.protocol !== \"wss:\") {\n throw new ConfigurationError(`${fieldName} must use http, https, ws, or wss protocol`, {\n fieldName,\n url,\n protocol: parsed.protocol,\n });\n }\n\n // Ensure hostname is present\n if (!parsed.hostname) {\n throw new ConfigurationError(`${fieldName} must include a hostname`, {\n fieldName,\n url,\n });\n }\n }\n catch (error) {\n if (error instanceof ConfigurationError) {\n throw error;\n }\n throw new ConfigurationError(`${fieldName} is not a valid URL: ${error}`, {\n fieldName,\n url,\n });\n }\n}\n\n/**\n * Validates a file path exists and is readable\n * @param filePath - The file path to validate\n * @param fieldName - Name of the field for error messages\n * @throws {ConfigurationError} If file doesn't exist or isn't readable\n */\nexport function validateFilePath(filePath: string, fieldName: string = \"File path\"): void {\n if (!filePath || typeof filePath !== \"string\") {\n throw new ConfigurationError(`${fieldName} is required and must be a string`, {\n fieldName,\n value: filePath,\n });\n }\n\n if (!fs.existsSync(filePath)) {\n throw new ConfigurationError(`${fieldName} does not exist: ${filePath}`, {\n fieldName,\n filePath,\n });\n }\n\n try {\n fs.accessSync(filePath, fs.constants.R_OK);\n }\n catch (error) {\n throw new ConfigurationError(`${fieldName} is not readable: ${filePath}`, {\n fieldName,\n filePath,\n error: String(error),\n });\n }\n}\n\n/**\n * Validates a PostgreSQL connection string\n * @param connectionString - The connection string to validate\n * @param fieldName - Name of the field for error messages\n * @throws {ConfigurationError} If connection string is invalid\n */\nexport function validatePostgresConnectionString(\n connectionString: string,\n fieldName: string = \"Database connection string\",\n): void {\n if (!connectionString || typeof connectionString !== \"string\") {\n throw new ConfigurationError(`${fieldName} is required and must be a string`, {\n fieldName,\n value: connectionString,\n });\n }\n\n // Basic PostgreSQL connection string format validation\n // Format: postgres://user:password@host:port/database\n const pgRegex = /^postgres(?:ql)?:\\/\\/(?:([^:]+)(?::([^@]+))?@)?([^:/]+)(?::(\\d+))?\\/(.+)$/;\n\n if (!pgRegex.test(connectionString)) {\n throw new ConfigurationError(\n `${fieldName} must be in format: postgres://user:password@host:port/database`,\n {\n fieldName,\n format: \"postgres://user:password@host:port/database\",\n },\n );\n }\n}\n\n/**\n * Validates a port number\n * @param port - The port number to validate\n * @param fieldName - Name of the field for error messages\n * @throws {ConfigurationError} If port is invalid\n */\nexport function validatePort(port: number, fieldName: string = \"Port\"): void {\n if (typeof port !== \"number\" || !Number.isInteger(port)) {\n throw new ConfigurationError(`${fieldName} must be an integer`, {\n fieldName,\n value: port,\n });\n }\n\n if (port < 1 || port > 65535) {\n throw new ConfigurationError(`${fieldName} must be between 1 and 65535`, {\n fieldName,\n value: port,\n min: 1,\n max: 65535,\n });\n }\n}\n\n/**\n * Validates a positive integer\n * @param value - The value to validate\n * @param fieldName - Name of the field for error messages\n * @throws {ConfigurationError} If value is not a positive integer\n */\nexport function validatePositiveInteger(value: number, fieldName: string = \"Value\"): void {\n if (typeof value !== \"number\" || !Number.isInteger(value) || value <= 0) {\n throw new ConfigurationError(`${fieldName} must be a positive integer`, {\n fieldName,\n value,\n });\n }\n}\n\n/**\n * Gets and validates the chain prefix from environment variables\n * @param defaultPrefix - Default prefix to use if environment variable is not set\n * @returns The validated chain prefix\n * @throws {ConfigurationError} If chain prefix is invalid\n */\nexport function getChainPrefix(defaultPrefix: string = \"cosmos\"): string {\n const prefix = process.env.CHAIN_PREFIX ?? defaultPrefix;\n\n if (!prefix || typeof prefix !== \"string\") {\n throw new ConfigurationError(\"CHAIN_PREFIX must be a non-empty string\", {\n value: prefix,\n defaultPrefix,\n });\n }\n\n // Validate prefix format (lowercase alphanumeric)\n if (!/^[a-z][a-z0-9]*$/.test(prefix)) {\n throw new ConfigurationError(\n \"CHAIN_PREFIX must start with lowercase letter and contain only lowercase letters and numbers\",\n {\n value: prefix,\n pattern: \"^[a-z][a-z0-9]*$\",\n },\n );\n }\n\n return prefix;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAiBA,SAAgB,YAAY,KAAa,YAAoB,OAAa;AACxE,KAAI,CAAC,OAAO,OAAO,QAAQ,SACzB,OAAM,IAAIA,iCAAmB,GAAG,UAAU,oCAAoC;EAC5E;EACA,OAAO;EACR,CAAC;AAGJ,KAAI;EACF,MAAM,SAAS,IAAI,IAAI,IAAI;AAG3B,MAAI,OAAO,aAAa,WAAW,OAAO,aAAa,YAAY,OAAO,aAAa,SAAS,OAAO,aAAa,OAClH,OAAM,IAAIA,iCAAmB,GAAG,UAAU,6CAA6C;GACrF;GACA;GACA,UAAU,OAAO;GAClB,CAAC;AAIJ,MAAI,CAAC,OAAO,SACV,OAAM,IAAIA,iCAAmB,GAAG,UAAU,2BAA2B;GACnE;GACA;GACD,CAAC;UAGC,OAAO;AACZ,MAAI,iBAAiBA,iCACnB,OAAM;AAER,QAAM,IAAIA,iCAAmB,GAAG,UAAU,uBAAuB,SAAS;GACxE;GACA;GACD,CAAC;;;;;;;;;AAUN,SAAgB,iBAAiB,UAAkB,YAAoB,aAAmB;AACxF,KAAI,CAAC,YAAY,OAAO,aAAa,SACnC,OAAM,IAAIA,iCAAmB,GAAG,UAAU,oCAAoC;EAC5E;EACA,OAAO;EACR,CAAC;AAGJ,KAAI,CAAC,GAAG,WAAW,SAAS,CAC1B,OAAM,IAAIA,iCAAmB,GAAG,UAAU,mBAAmB,YAAY;EACvE;EACA;EACD,CAAC;AAGJ,KAAI;AACF,KAAG,WAAW,UAAU,GAAG,UAAU,KAAK;UAErC,OAAO;AACZ,QAAM,IAAIA,iCAAmB,GAAG,UAAU,oBAAoB,YAAY;GACxE;GACA;GACA,OAAO,OAAO,MAAM;GACrB,CAAC;;;;;;;;;AAUN,SAAgB,iCACd,kBACA,YAAoB,8BACd;AACN,KAAI,CAAC,oBAAoB,OAAO,qBAAqB,SACnD,OAAM,IAAIA,iCAAmB,GAAG,UAAU,oCAAoC;EAC5E;EACA,OAAO;EACR,CAAC;AAOJ,KAAI,CAFY,4EAEH,KAAK,iBAAiB,CACjC,OAAM,IAAIA,iCACR,GAAG,UAAU,kEACb;EACE;EACA,QAAQ;EACT,CACF;;;;;;;;AAUL,SAAgB,aAAa,MAAc,YAAoB,QAAc;AAC3E,KAAI,OAAO,SAAS,YAAY,CAAC,OAAO,UAAU,KAAK,CACrD,OAAM,IAAIA,iCAAmB,GAAG,UAAU,sBAAsB;EAC9D;EACA,OAAO;EACR,CAAC;AAGJ,KAAI,OAAO,KAAK,OAAO,MACrB,OAAM,IAAIA,iCAAmB,GAAG,UAAU,+BAA+B;EACvE;EACA,OAAO;EACP,KAAK;EACL,KAAK;EACN,CAAC;;;;;;;;AAUN,SAAgB,wBAAwB,OAAe,YAAoB,SAAe;AACxF,KAAI,OAAO,UAAU,YAAY,CAAC,OAAO,UAAU,MAAM,IAAI,SAAS,EACpE,OAAM,IAAIA,iCAAmB,GAAG,UAAU,8BAA8B;EACtE;EACA;EACD,CAAC;;;;;;;;AAUN,SAAgB,eAAe,gBAAwB,UAAkB;CACvE,MAAM,SAAS,QAAQ,IAAI,gBAAgB;AAE3C,KAAI,CAAC,UAAU,OAAO,WAAW,SAC/B,OAAM,IAAIA,iCAAmB,2CAA2C;EACtE,OAAO;EACP;EACD,CAAC;AAIJ,KAAI,CAAC,mBAAmB,KAAK,OAAO,CAClC,OAAM,IAAIA,iCACR,gGACA;EACE,OAAO;EACP,SAAS;EACV,CACF;AAGH,QAAO"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
declare namespace index_d_exports {
|
|
2
|
+
export { getChainPrefix, validateFilePath, validatePort, validatePositiveInteger, validatePostgresConnectionString, validateUrl };
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Configuration validation utilities for the Eclesia indexer
|
|
6
|
+
* Validates configuration parameters before initialization
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Validates a URL string
|
|
10
|
+
* @param url - The URL to validate
|
|
11
|
+
* @param fieldName - Name of the field for error messages
|
|
12
|
+
* @throws {ConfigurationError} If URL is invalid
|
|
13
|
+
*/
|
|
14
|
+
declare function validateUrl(url: string, fieldName?: string): void;
|
|
15
|
+
/**
|
|
16
|
+
* Validates a file path exists and is readable
|
|
17
|
+
* @param filePath - The file path to validate
|
|
18
|
+
* @param fieldName - Name of the field for error messages
|
|
19
|
+
* @throws {ConfigurationError} If file doesn't exist or isn't readable
|
|
20
|
+
*/
|
|
21
|
+
declare function validateFilePath(filePath: string, fieldName?: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* Validates a PostgreSQL connection string
|
|
24
|
+
* @param connectionString - The connection string to validate
|
|
25
|
+
* @param fieldName - Name of the field for error messages
|
|
26
|
+
* @throws {ConfigurationError} If connection string is invalid
|
|
27
|
+
*/
|
|
28
|
+
declare function validatePostgresConnectionString(connectionString: string, fieldName?: string): void;
|
|
29
|
+
/**
|
|
30
|
+
* Validates a port number
|
|
31
|
+
* @param port - The port number to validate
|
|
32
|
+
* @param fieldName - Name of the field for error messages
|
|
33
|
+
* @throws {ConfigurationError} If port is invalid
|
|
34
|
+
*/
|
|
35
|
+
declare function validatePort(port: number, fieldName?: string): void;
|
|
36
|
+
/**
|
|
37
|
+
* Validates a positive integer
|
|
38
|
+
* @param value - The value to validate
|
|
39
|
+
* @param fieldName - Name of the field for error messages
|
|
40
|
+
* @throws {ConfigurationError} If value is not a positive integer
|
|
41
|
+
*/
|
|
42
|
+
declare function validatePositiveInteger(value: number, fieldName?: string): void;
|
|
43
|
+
/**
|
|
44
|
+
* Gets and validates the chain prefix from environment variables
|
|
45
|
+
* @param defaultPrefix - Default prefix to use if environment variable is not set
|
|
46
|
+
* @returns The validated chain prefix
|
|
47
|
+
* @throws {ConfigurationError} If chain prefix is invalid
|
|
48
|
+
*/
|
|
49
|
+
declare function getChainPrefix(defaultPrefix?: string): string;
|
|
50
|
+
//#endregion
|
|
51
|
+
export { index_d_exports };
|
|
52
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/validation/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;iBAiBgB,WAAA;AAAhB;AA6CA;AAiCA;AAgCA;AAwBA;AAeA;iBAxGgB,gBAAA;;;;;;;iBAiCA,gCAAA;;;;;;;iBAgCA,YAAA;;;;;;;iBAwBA,uBAAA;;;;;;;iBAeA,cAAA"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
declare namespace index_d_exports {
|
|
2
|
+
export { getChainPrefix, validateFilePath, validatePort, validatePositiveInteger, validatePostgresConnectionString, validateUrl };
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Configuration validation utilities for the Eclesia indexer
|
|
6
|
+
* Validates configuration parameters before initialization
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Validates a URL string
|
|
10
|
+
* @param url - The URL to validate
|
|
11
|
+
* @param fieldName - Name of the field for error messages
|
|
12
|
+
* @throws {ConfigurationError} If URL is invalid
|
|
13
|
+
*/
|
|
14
|
+
declare function validateUrl(url: string, fieldName?: string): void;
|
|
15
|
+
/**
|
|
16
|
+
* Validates a file path exists and is readable
|
|
17
|
+
* @param filePath - The file path to validate
|
|
18
|
+
* @param fieldName - Name of the field for error messages
|
|
19
|
+
* @throws {ConfigurationError} If file doesn't exist or isn't readable
|
|
20
|
+
*/
|
|
21
|
+
declare function validateFilePath(filePath: string, fieldName?: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* Validates a PostgreSQL connection string
|
|
24
|
+
* @param connectionString - The connection string to validate
|
|
25
|
+
* @param fieldName - Name of the field for error messages
|
|
26
|
+
* @throws {ConfigurationError} If connection string is invalid
|
|
27
|
+
*/
|
|
28
|
+
declare function validatePostgresConnectionString(connectionString: string, fieldName?: string): void;
|
|
29
|
+
/**
|
|
30
|
+
* Validates a port number
|
|
31
|
+
* @param port - The port number to validate
|
|
32
|
+
* @param fieldName - Name of the field for error messages
|
|
33
|
+
* @throws {ConfigurationError} If port is invalid
|
|
34
|
+
*/
|
|
35
|
+
declare function validatePort(port: number, fieldName?: string): void;
|
|
36
|
+
/**
|
|
37
|
+
* Validates a positive integer
|
|
38
|
+
* @param value - The value to validate
|
|
39
|
+
* @param fieldName - Name of the field for error messages
|
|
40
|
+
* @throws {ConfigurationError} If value is not a positive integer
|
|
41
|
+
*/
|
|
42
|
+
declare function validatePositiveInteger(value: number, fieldName?: string): void;
|
|
43
|
+
/**
|
|
44
|
+
* Gets and validates the chain prefix from environment variables
|
|
45
|
+
* @param defaultPrefix - Default prefix to use if environment variable is not set
|
|
46
|
+
* @returns The validated chain prefix
|
|
47
|
+
* @throws {ConfigurationError} If chain prefix is invalid
|
|
48
|
+
*/
|
|
49
|
+
declare function getChainPrefix(defaultPrefix?: string): string;
|
|
50
|
+
//#endregion
|
|
51
|
+
export { index_d_exports };
|
|
52
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/validation/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;iBAiBgB,WAAA;AAAhB;AA6CA;AAiCA;AAgCA;AAwBA;AAeA;iBAxGgB,gBAAA;;;;;;;iBAiCA,gCAAA;;;;;;;iBAgCA,YAAA;;;;;;;iBAwBA,uBAAA;;;;;;;iBAeA,cAAA"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { __export } from "../_virtual/rolldown_runtime.js";
|
|
2
|
+
import { ConfigurationError } from "../errors/index.js";
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
|
|
5
|
+
//#region src/validation/index.ts
|
|
6
|
+
/**
|
|
7
|
+
* Configuration validation utilities for the Eclesia indexer
|
|
8
|
+
* Validates configuration parameters before initialization
|
|
9
|
+
*/
|
|
10
|
+
var validation_exports = /* @__PURE__ */ __export({
|
|
11
|
+
getChainPrefix: () => getChainPrefix,
|
|
12
|
+
validateFilePath: () => validateFilePath,
|
|
13
|
+
validatePort: () => validatePort,
|
|
14
|
+
validatePositiveInteger: () => validatePositiveInteger,
|
|
15
|
+
validatePostgresConnectionString: () => validatePostgresConnectionString,
|
|
16
|
+
validateUrl: () => validateUrl
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* Validates a URL string
|
|
20
|
+
* @param url - The URL to validate
|
|
21
|
+
* @param fieldName - Name of the field for error messages
|
|
22
|
+
* @throws {ConfigurationError} If URL is invalid
|
|
23
|
+
*/
|
|
24
|
+
function validateUrl(url, fieldName = "URL") {
|
|
25
|
+
if (!url || typeof url !== "string") throw new ConfigurationError(`${fieldName} is required and must be a string`, {
|
|
26
|
+
fieldName,
|
|
27
|
+
value: url
|
|
28
|
+
});
|
|
29
|
+
try {
|
|
30
|
+
const parsed = new URL(url);
|
|
31
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:" && parsed.protocol !== "ws:" && parsed.protocol !== "wss:") throw new ConfigurationError(`${fieldName} must use http, https, ws, or wss protocol`, {
|
|
32
|
+
fieldName,
|
|
33
|
+
url,
|
|
34
|
+
protocol: parsed.protocol
|
|
35
|
+
});
|
|
36
|
+
if (!parsed.hostname) throw new ConfigurationError(`${fieldName} must include a hostname`, {
|
|
37
|
+
fieldName,
|
|
38
|
+
url
|
|
39
|
+
});
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (error instanceof ConfigurationError) throw error;
|
|
42
|
+
throw new ConfigurationError(`${fieldName} is not a valid URL: ${error}`, {
|
|
43
|
+
fieldName,
|
|
44
|
+
url
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Validates a file path exists and is readable
|
|
50
|
+
* @param filePath - The file path to validate
|
|
51
|
+
* @param fieldName - Name of the field for error messages
|
|
52
|
+
* @throws {ConfigurationError} If file doesn't exist or isn't readable
|
|
53
|
+
*/
|
|
54
|
+
function validateFilePath(filePath, fieldName = "File path") {
|
|
55
|
+
if (!filePath || typeof filePath !== "string") throw new ConfigurationError(`${fieldName} is required and must be a string`, {
|
|
56
|
+
fieldName,
|
|
57
|
+
value: filePath
|
|
58
|
+
});
|
|
59
|
+
if (!fs.existsSync(filePath)) throw new ConfigurationError(`${fieldName} does not exist: ${filePath}`, {
|
|
60
|
+
fieldName,
|
|
61
|
+
filePath
|
|
62
|
+
});
|
|
63
|
+
try {
|
|
64
|
+
fs.accessSync(filePath, fs.constants.R_OK);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
throw new ConfigurationError(`${fieldName} is not readable: ${filePath}`, {
|
|
67
|
+
fieldName,
|
|
68
|
+
filePath,
|
|
69
|
+
error: String(error)
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Validates a PostgreSQL connection string
|
|
75
|
+
* @param connectionString - The connection string to validate
|
|
76
|
+
* @param fieldName - Name of the field for error messages
|
|
77
|
+
* @throws {ConfigurationError} If connection string is invalid
|
|
78
|
+
*/
|
|
79
|
+
function validatePostgresConnectionString(connectionString, fieldName = "Database connection string") {
|
|
80
|
+
if (!connectionString || typeof connectionString !== "string") throw new ConfigurationError(`${fieldName} is required and must be a string`, {
|
|
81
|
+
fieldName,
|
|
82
|
+
value: connectionString
|
|
83
|
+
});
|
|
84
|
+
if (!/^postgres(?:ql)?:\/\/(?:([^:]+)(?::([^@]+))?@)?([^:/]+)(?::(\d+))?\/(.+)$/.test(connectionString)) throw new ConfigurationError(`${fieldName} must be in format: postgres://user:password@host:port/database`, {
|
|
85
|
+
fieldName,
|
|
86
|
+
format: "postgres://user:password@host:port/database"
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Validates a port number
|
|
91
|
+
* @param port - The port number to validate
|
|
92
|
+
* @param fieldName - Name of the field for error messages
|
|
93
|
+
* @throws {ConfigurationError} If port is invalid
|
|
94
|
+
*/
|
|
95
|
+
function validatePort(port, fieldName = "Port") {
|
|
96
|
+
if (typeof port !== "number" || !Number.isInteger(port)) throw new ConfigurationError(`${fieldName} must be an integer`, {
|
|
97
|
+
fieldName,
|
|
98
|
+
value: port
|
|
99
|
+
});
|
|
100
|
+
if (port < 1 || port > 65535) throw new ConfigurationError(`${fieldName} must be between 1 and 65535`, {
|
|
101
|
+
fieldName,
|
|
102
|
+
value: port,
|
|
103
|
+
min: 1,
|
|
104
|
+
max: 65535
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Validates a positive integer
|
|
109
|
+
* @param value - The value to validate
|
|
110
|
+
* @param fieldName - Name of the field for error messages
|
|
111
|
+
* @throws {ConfigurationError} If value is not a positive integer
|
|
112
|
+
*/
|
|
113
|
+
function validatePositiveInteger(value, fieldName = "Value") {
|
|
114
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) throw new ConfigurationError(`${fieldName} must be a positive integer`, {
|
|
115
|
+
fieldName,
|
|
116
|
+
value
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Gets and validates the chain prefix from environment variables
|
|
121
|
+
* @param defaultPrefix - Default prefix to use if environment variable is not set
|
|
122
|
+
* @returns The validated chain prefix
|
|
123
|
+
* @throws {ConfigurationError} If chain prefix is invalid
|
|
124
|
+
*/
|
|
125
|
+
function getChainPrefix(defaultPrefix = "cosmos") {
|
|
126
|
+
const prefix = process.env.CHAIN_PREFIX ?? defaultPrefix;
|
|
127
|
+
if (!prefix || typeof prefix !== "string") throw new ConfigurationError("CHAIN_PREFIX must be a non-empty string", {
|
|
128
|
+
value: prefix,
|
|
129
|
+
defaultPrefix
|
|
130
|
+
});
|
|
131
|
+
if (!/^[a-z][a-z0-9]*$/.test(prefix)) throw new ConfigurationError("CHAIN_PREFIX must start with lowercase letter and contain only lowercase letters and numbers", {
|
|
132
|
+
value: prefix,
|
|
133
|
+
pattern: "^[a-z][a-z0-9]*$"
|
|
134
|
+
});
|
|
135
|
+
return prefix;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
//#endregion
|
|
139
|
+
export { validateFilePath, validatePort, validatePositiveInteger, validateUrl, validation_exports };
|
|
140
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/validation/index.ts"],"sourcesContent":["/**\n * Configuration validation utilities for the Eclesia indexer\n * Validates configuration parameters before initialization\n */\n\nimport * as fs from \"node:fs\";\n\nimport {\n ConfigurationError,\n} from \"../errors/index.js\";\n\n/**\n * Validates a URL string\n * @param url - The URL to validate\n * @param fieldName - Name of the field for error messages\n * @throws {ConfigurationError} If URL is invalid\n */\nexport function validateUrl(url: string, fieldName: string = \"URL\"): void {\n if (!url || typeof url !== \"string\") {\n throw new ConfigurationError(`${fieldName} is required and must be a string`, {\n fieldName,\n value: url,\n });\n }\n\n try {\n const parsed = new URL(url);\n\n // Ensure protocol is http or https\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\" && parsed.protocol !== \"ws:\" && parsed.protocol !== \"wss:\") {\n throw new ConfigurationError(`${fieldName} must use http, https, ws, or wss protocol`, {\n fieldName,\n url,\n protocol: parsed.protocol,\n });\n }\n\n // Ensure hostname is present\n if (!parsed.hostname) {\n throw new ConfigurationError(`${fieldName} must include a hostname`, {\n fieldName,\n url,\n });\n }\n }\n catch (error) {\n if (error instanceof ConfigurationError) {\n throw error;\n }\n throw new ConfigurationError(`${fieldName} is not a valid URL: ${error}`, {\n fieldName,\n url,\n });\n }\n}\n\n/**\n * Validates a file path exists and is readable\n * @param filePath - The file path to validate\n * @param fieldName - Name of the field for error messages\n * @throws {ConfigurationError} If file doesn't exist or isn't readable\n */\nexport function validateFilePath(filePath: string, fieldName: string = \"File path\"): void {\n if (!filePath || typeof filePath !== \"string\") {\n throw new ConfigurationError(`${fieldName} is required and must be a string`, {\n fieldName,\n value: filePath,\n });\n }\n\n if (!fs.existsSync(filePath)) {\n throw new ConfigurationError(`${fieldName} does not exist: ${filePath}`, {\n fieldName,\n filePath,\n });\n }\n\n try {\n fs.accessSync(filePath, fs.constants.R_OK);\n }\n catch (error) {\n throw new ConfigurationError(`${fieldName} is not readable: ${filePath}`, {\n fieldName,\n filePath,\n error: String(error),\n });\n }\n}\n\n/**\n * Validates a PostgreSQL connection string\n * @param connectionString - The connection string to validate\n * @param fieldName - Name of the field for error messages\n * @throws {ConfigurationError} If connection string is invalid\n */\nexport function validatePostgresConnectionString(\n connectionString: string,\n fieldName: string = \"Database connection string\",\n): void {\n if (!connectionString || typeof connectionString !== \"string\") {\n throw new ConfigurationError(`${fieldName} is required and must be a string`, {\n fieldName,\n value: connectionString,\n });\n }\n\n // Basic PostgreSQL connection string format validation\n // Format: postgres://user:password@host:port/database\n const pgRegex = /^postgres(?:ql)?:\\/\\/(?:([^:]+)(?::([^@]+))?@)?([^:/]+)(?::(\\d+))?\\/(.+)$/;\n\n if (!pgRegex.test(connectionString)) {\n throw new ConfigurationError(\n `${fieldName} must be in format: postgres://user:password@host:port/database`,\n {\n fieldName,\n format: \"postgres://user:password@host:port/database\",\n },\n );\n }\n}\n\n/**\n * Validates a port number\n * @param port - The port number to validate\n * @param fieldName - Name of the field for error messages\n * @throws {ConfigurationError} If port is invalid\n */\nexport function validatePort(port: number, fieldName: string = \"Port\"): void {\n if (typeof port !== \"number\" || !Number.isInteger(port)) {\n throw new ConfigurationError(`${fieldName} must be an integer`, {\n fieldName,\n value: port,\n });\n }\n\n if (port < 1 || port > 65535) {\n throw new ConfigurationError(`${fieldName} must be between 1 and 65535`, {\n fieldName,\n value: port,\n min: 1,\n max: 65535,\n });\n }\n}\n\n/**\n * Validates a positive integer\n * @param value - The value to validate\n * @param fieldName - Name of the field for error messages\n * @throws {ConfigurationError} If value is not a positive integer\n */\nexport function validatePositiveInteger(value: number, fieldName: string = \"Value\"): void {\n if (typeof value !== \"number\" || !Number.isInteger(value) || value <= 0) {\n throw new ConfigurationError(`${fieldName} must be a positive integer`, {\n fieldName,\n value,\n });\n }\n}\n\n/**\n * Gets and validates the chain prefix from environment variables\n * @param defaultPrefix - Default prefix to use if environment variable is not set\n * @returns The validated chain prefix\n * @throws {ConfigurationError} If chain prefix is invalid\n */\nexport function getChainPrefix(defaultPrefix: string = \"cosmos\"): string {\n const prefix = process.env.CHAIN_PREFIX ?? defaultPrefix;\n\n if (!prefix || typeof prefix !== \"string\") {\n throw new ConfigurationError(\"CHAIN_PREFIX must be a non-empty string\", {\n value: prefix,\n defaultPrefix,\n });\n }\n\n // Validate prefix format (lowercase alphanumeric)\n if (!/^[a-z][a-z0-9]*$/.test(prefix)) {\n throw new ConfigurationError(\n \"CHAIN_PREFIX must start with lowercase letter and contain only lowercase letters and numbers\",\n {\n value: prefix,\n pattern: \"^[a-z][a-z0-9]*$\",\n },\n );\n }\n\n return prefix;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAiBA,SAAgB,YAAY,KAAa,YAAoB,OAAa;AACxE,KAAI,CAAC,OAAO,OAAO,QAAQ,SACzB,OAAM,IAAI,mBAAmB,GAAG,UAAU,oCAAoC;EAC5E;EACA,OAAO;EACR,CAAC;AAGJ,KAAI;EACF,MAAM,SAAS,IAAI,IAAI,IAAI;AAG3B,MAAI,OAAO,aAAa,WAAW,OAAO,aAAa,YAAY,OAAO,aAAa,SAAS,OAAO,aAAa,OAClH,OAAM,IAAI,mBAAmB,GAAG,UAAU,6CAA6C;GACrF;GACA;GACA,UAAU,OAAO;GAClB,CAAC;AAIJ,MAAI,CAAC,OAAO,SACV,OAAM,IAAI,mBAAmB,GAAG,UAAU,2BAA2B;GACnE;GACA;GACD,CAAC;UAGC,OAAO;AACZ,MAAI,iBAAiB,mBACnB,OAAM;AAER,QAAM,IAAI,mBAAmB,GAAG,UAAU,uBAAuB,SAAS;GACxE;GACA;GACD,CAAC;;;;;;;;;AAUN,SAAgB,iBAAiB,UAAkB,YAAoB,aAAmB;AACxF,KAAI,CAAC,YAAY,OAAO,aAAa,SACnC,OAAM,IAAI,mBAAmB,GAAG,UAAU,oCAAoC;EAC5E;EACA,OAAO;EACR,CAAC;AAGJ,KAAI,CAAC,GAAG,WAAW,SAAS,CAC1B,OAAM,IAAI,mBAAmB,GAAG,UAAU,mBAAmB,YAAY;EACvE;EACA;EACD,CAAC;AAGJ,KAAI;AACF,KAAG,WAAW,UAAU,GAAG,UAAU,KAAK;UAErC,OAAO;AACZ,QAAM,IAAI,mBAAmB,GAAG,UAAU,oBAAoB,YAAY;GACxE;GACA;GACA,OAAO,OAAO,MAAM;GACrB,CAAC;;;;;;;;;AAUN,SAAgB,iCACd,kBACA,YAAoB,8BACd;AACN,KAAI,CAAC,oBAAoB,OAAO,qBAAqB,SACnD,OAAM,IAAI,mBAAmB,GAAG,UAAU,oCAAoC;EAC5E;EACA,OAAO;EACR,CAAC;AAOJ,KAAI,CAFY,4EAEH,KAAK,iBAAiB,CACjC,OAAM,IAAI,mBACR,GAAG,UAAU,kEACb;EACE;EACA,QAAQ;EACT,CACF;;;;;;;;AAUL,SAAgB,aAAa,MAAc,YAAoB,QAAc;AAC3E,KAAI,OAAO,SAAS,YAAY,CAAC,OAAO,UAAU,KAAK,CACrD,OAAM,IAAI,mBAAmB,GAAG,UAAU,sBAAsB;EAC9D;EACA,OAAO;EACR,CAAC;AAGJ,KAAI,OAAO,KAAK,OAAO,MACrB,OAAM,IAAI,mBAAmB,GAAG,UAAU,+BAA+B;EACvE;EACA,OAAO;EACP,KAAK;EACL,KAAK;EACN,CAAC;;;;;;;;AAUN,SAAgB,wBAAwB,OAAe,YAAoB,SAAe;AACxF,KAAI,OAAO,UAAU,YAAY,CAAC,OAAO,UAAU,MAAM,IAAI,SAAS,EACpE,OAAM,IAAI,mBAAmB,GAAG,UAAU,8BAA8B;EACtE;EACA;EACD,CAAC;;;;;;;;AAUN,SAAgB,eAAe,gBAAwB,UAAkB;CACvE,MAAM,SAAS,QAAQ,IAAI,gBAAgB;AAE3C,KAAI,CAAC,UAAU,OAAO,WAAW,SAC/B,OAAM,IAAI,mBAAmB,2CAA2C;EACtE,OAAO;EACP;EACD,CAAC;AAIJ,KAAI,CAAC,mBAAmB,KAAK,OAAO,CAClC,OAAM,IAAI,mBACR,gGACA;EACE,OAAO;EACP,SAAS;EACV,CACF;AAGH,QAAO"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eclesia/indexer-engine",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.0-next.1",
|
|
4
4
|
"description": "Core eclesia indexer engine",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist/",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"cosmjs-types": "^0.10.1",
|
|
41
41
|
"dayjs": "^1.11.18",
|
|
42
42
|
"fastify": "^5.6.0",
|
|
43
|
+
"prom-client": "^15.1.3",
|
|
43
44
|
"stream-chain": "^3.4.0",
|
|
44
45
|
"stream-json": "^1.9.1",
|
|
45
46
|
"uuid": "^13.0.0",
|
|
@@ -65,6 +66,7 @@
|
|
|
65
66
|
"lint": "eslint",
|
|
66
67
|
"lint:fix": "eslint --fix",
|
|
67
68
|
"test": "vitest",
|
|
69
|
+
"typecheck": "tsc --noEmit",
|
|
68
70
|
"start": "node dist/index.mjs"
|
|
69
71
|
}
|
|
70
72
|
}
|