@eclesia/indexer-engine 2.9.9 → 2.10.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/constants.cjs +74 -0
  2. package/dist/constants.cjs.map +1 -0
  3. package/dist/constants.d.cts +68 -0
  4. package/dist/constants.d.cts.map +1 -0
  5. package/dist/constants.d.ts +68 -0
  6. package/dist/constants.d.ts.map +1 -0
  7. package/dist/constants.js +64 -0
  8. package/dist/constants.js.map +1 -0
  9. package/dist/emitter/index.cjs +0 -1
  10. package/dist/emitter/index.cjs.map +1 -1
  11. package/dist/errors/index.cjs +107 -0
  12. package/dist/errors/index.cjs.map +1 -0
  13. package/dist/errors/index.d.cts +75 -0
  14. package/dist/errors/index.d.cts.map +1 -0
  15. package/dist/errors/index.d.ts +75 -0
  16. package/dist/errors/index.d.ts.map +1 -0
  17. package/dist/errors/index.js +100 -0
  18. package/dist/errors/index.js.map +1 -0
  19. package/dist/index.cjs +38 -10
  20. package/dist/index.d.cts +5 -1
  21. package/dist/index.d.ts +5 -1
  22. package/dist/index.js +5 -1
  23. package/dist/indexer/index.cjs +51 -27
  24. package/dist/indexer/index.cjs.map +1 -1
  25. package/dist/indexer/index.d.cts +1 -0
  26. package/dist/indexer/index.d.cts.map +1 -1
  27. package/dist/indexer/index.d.ts +1 -0
  28. package/dist/indexer/index.d.ts.map +1 -1
  29. package/dist/indexer/index.js +51 -20
  30. package/dist/indexer/index.js.map +1 -1
  31. package/dist/metrics/index.cjs +146 -0
  32. package/dist/metrics/index.cjs.map +1 -0
  33. package/dist/metrics/index.d.cts +56 -0
  34. package/dist/metrics/index.d.cts.map +1 -0
  35. package/dist/metrics/index.d.ts +56 -0
  36. package/dist/metrics/index.d.ts.map +1 -0
  37. package/dist/metrics/index.js +145 -0
  38. package/dist/metrics/index.js.map +1 -0
  39. package/dist/promise-queue/index.cjs +6 -4
  40. package/dist/promise-queue/index.cjs.map +1 -1
  41. package/dist/promise-queue/index.d.cts +6 -2
  42. package/dist/promise-queue/index.d.cts.map +1 -1
  43. package/dist/promise-queue/index.d.ts +6 -2
  44. package/dist/promise-queue/index.d.ts.map +1 -1
  45. package/dist/promise-queue/index.js +6 -4
  46. package/dist/promise-queue/index.js.map +1 -1
  47. package/dist/types/index.cjs.map +1 -1
  48. package/dist/types/index.d.cts +6 -0
  49. package/dist/types/index.d.cts.map +1 -1
  50. package/dist/types/index.d.ts +6 -0
  51. package/dist/types/index.d.ts.map +1 -1
  52. package/dist/types/index.js.map +1 -1
  53. package/dist/utils/bech32.cjs +0 -1
  54. package/dist/utils/bech32.cjs.map +1 -1
  55. package/dist/utils/index.cjs.map +1 -1
  56. package/dist/utils/index.js.map +1 -1
  57. package/dist/validation/index.cjs +150 -0
  58. package/dist/validation/index.cjs.map +1 -0
  59. package/dist/validation/index.d.cts +52 -0
  60. package/dist/validation/index.d.cts.map +1 -0
  61. package/dist/validation/index.d.ts +52 -0
  62. package/dist/validation/index.d.ts.map +1 -0
  63. package/dist/validation/index.js +140 -0
  64. package/dist/validation/index.js.map +1 -0
  65. 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.9.9",
3
+ "version": "2.10.0-next.0",
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
  }