@toxplanet/pegasus-sdk 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/search.js CHANGED
@@ -1,19 +1,293 @@
1
+ const { logInfo, logError } = require('@toxplanet/tphelper/logging');
2
+
3
+ /**
4
+ * Detect if query looks like a CAS number (numbers with - or / separators)
5
+ * Returns array of alternative formats to try
6
+ *
7
+ * CAS format: XXXXXXX-XX-X (registry-sequence-check)
8
+ * - First part: 2-7 digits (registry number)
9
+ * - Second part: ALWAYS 2 digits (zero-padded)
10
+ * - Third part: ALWAYS 1 digit (check digit)
11
+ */
12
+ function getCasNumberVariations(query) {
13
+ // Check if it's all numbers and separators (-, /)
14
+ if (!/^[\d\-\/]+$/.test(query)) {
15
+ return [query]; // Not a CAS-like format, return as-is
16
+ }
17
+
18
+ // Check if it has at least one separator
19
+ if (!query.includes('-') && !query.includes('/')) {
20
+ return [query]; // No separator, return as-is
21
+ }
22
+
23
+ // Generate variations
24
+ const variations = new Set();
25
+
26
+ // Add original
27
+ variations.add(query);
28
+
29
+ // Split by any separator
30
+ const parts = query.split(/[-\/]/);
31
+
32
+ if (parts.length === 3) {
33
+ // Three parts detected
34
+ // Could be:
35
+ // 1. Standard: registry-sequence-check (e.g., "7440-06-4")
36
+ // 2. Reversed: sequence/check/registry (e.g., "6/4/7440")
37
+
38
+ const [part1, part2, part3] = parts;
39
+
40
+ // Check if it looks like reversed format
41
+ // (small first part, small second part, large third part)
42
+ const isLikelyReversed = part1.length <= 2 && part2.length <= 2 && part3.length >= 3;
43
+
44
+ if (isLikelyReversed) {
45
+ // Format: sequence/check/registry → registry-sequence-check
46
+ const registry = part3;
47
+ const sequence = part1.padStart(2, '0'); // Zero-pad to 2 digits
48
+ const check = part2;
49
+
50
+ // Add properly formatted CAS
51
+ variations.add(`${registry}-${sequence}-${check}`);
52
+ variations.add(`${registry}/${sequence}/${check}`);
53
+ } else {
54
+ // Looks like standard format, try both separators
55
+ const registry = part1;
56
+ const sequence = part2.padStart(2, '0'); // Ensure 2 digits
57
+ const check = part3;
58
+
59
+ variations.add(`${registry}-${sequence}-${check}`);
60
+ variations.add(`${registry}/${sequence}/${check}`);
61
+ }
62
+
63
+ // Also try with different separator on original parts
64
+ variations.add(parts.join('-'));
65
+ variations.add(parts.join('/'));
66
+ } else if (parts.length === 2) {
67
+ // Two parts - just try both separators
68
+ variations.add(parts.join('-'));
69
+ variations.add(parts.join('/'));
70
+ }
71
+
72
+ return Array.from(variations);
73
+ }
74
+
1
75
  class SearchService {
2
- constructor(connection) {}
76
+ constructor(connection) {
77
+ this.connection = connection;
78
+ }
79
+
80
+ /**
81
+ * Search chemicals using OpenSearch with configurable boost parameters
82
+ * @param {string} query - Search query string
83
+ * @param {Object} options - Search options
84
+ * @param {number} options.limit - Maximum number of results (default: 10)
85
+ * @param {number} options.casExact - Boost for exact CAS matches (default: 50)
86
+ * @param {number} options.casPrefix - Boost for CAS prefix matches (default: 10)
87
+ * @param {number} options.nameExact - Boost for exact name matches (default: 40)
88
+ * @param {number} options.namePrefix - Boost for name prefix matches (default: 8)
89
+ * @param {number} options.identifierExact - Boost for exact identifier matches (default: 30)
90
+ * @param {number} options.identifierPrefix - Boost for identifier prefix matches (default: 5)
91
+ * @param {number} options.synonymExact - Boost for exact synonym matches (default: 100)
92
+ * @param {number} options.synonymPrefix - Boost for synonym prefix matches (default: 3)
93
+ * @returns {Promise<Object>} Search results with chemicals array
94
+ */
95
+ async searchChemicals(query, options = {}) {
96
+ if (!query) {
97
+ return { results: [] };
98
+ }
3
99
 
4
- async searchChemicals(searchTerm, searchType, limit, offset) {}
100
+ // Extract options with defaults
101
+ const limit = options.limit || 10;
102
+ const casExact = options.casExact !== undefined ? options.casExact : 50;
103
+ const casPrefix = options.casPrefix !== undefined ? options.casPrefix : 10;
104
+ const nameExact = options.nameExact !== undefined ? options.nameExact : 40;
105
+ const namePrefix = options.namePrefix !== undefined ? options.namePrefix : 8;
106
+ const identifierExact = options.identifierExact !== undefined ? options.identifierExact : 30;
107
+ const identifierPrefix = options.identifierPrefix !== undefined ? options.identifierPrefix : 5;
108
+ const synonymExact = options.synonymExact !== undefined ? options.synonymExact : 100;
109
+ const synonymPrefix = options.synonymPrefix !== undefined ? options.synonymPrefix : 3;
5
110
 
6
- async searchStartsWith(searchTerm, limit) {}
111
+ try {
112
+ const opensearchClient = this.connection.getOpenSearchClient();
113
+
114
+ // Get CAS number variations (if applicable)
115
+ const queryVariations = getCasNumberVariations(query);
116
+
117
+ // Log if we're trying multiple variations
118
+ if (queryVariations.length > 1) {
119
+ logInfo('pegasus-sdk', `CAS format detection: trying ${queryVariations.length} variations for "${query}": ${JSON.stringify(queryVariations)}`);
120
+ }
121
+
122
+ // Build should clauses for all query variations
123
+ const shouldClauses = [];
124
+
125
+ for (const queryVariation of queryVariations) {
126
+ // Exact matches (configurable priority)
127
+ shouldClauses.push(
128
+ { term: { 'cas_numbers': { value: queryVariation, boost: casExact } } },
129
+ { term: { 'chemical_name.keyword': { value: queryVariation, boost: nameExact, case_insensitive: true } } },
130
+ { term: { 'identifier_values': { value: queryVariation, boost: identifierExact } } },
131
+ { term: { 'synonyms.keyword': { value: queryVariation, boost: synonymExact, case_insensitive: true } } },
132
+ // Prefix matches (configurable priority)
133
+ { prefix: { 'cas_numbers': { value: queryVariation, boost: casPrefix } } },
134
+ { prefix: { 'chemical_name.keyword': { value: queryVariation, boost: namePrefix, case_insensitive: true } } },
135
+ { prefix: { 'identifier_values': { value: queryVariation, boost: identifierPrefix } } },
136
+ { prefix: { 'synonyms.keyword': { value: queryVariation, boost: synonymPrefix, case_insensitive: true } } }
137
+ );
138
+ }
139
+
140
+ const indexName = this.connection.getOpenSearchIndex();
141
+
142
+ const response = await opensearchClient.search({
143
+ index: indexName,
144
+ body: {
145
+ size: limit,
146
+ query: {
147
+ bool: {
148
+ should: shouldClauses,
149
+ minimum_should_match: 1
150
+ }
151
+ },
152
+ _source: ['postgres_id', 'chemical_name', 'cas_numbers', 'identifier_values', 'synonyms']
153
+ }
154
+ });
7
155
 
8
- async searchContains(searchTerm, limit) {}
156
+ const hits = response.body?.hits?.hits || [];
157
+ const results = hits.map((hit) => ({
158
+ id: hit._source.postgres_id,
159
+ name: hit._source.chemical_name,
160
+ cas: hit._source.cas_numbers || [],
161
+ identifiers: hit._source.identifier_values || [],
162
+ synonyms: hit._source.synonyms || [],
163
+ score: hit._score
164
+ }));
9
165
 
10
- async searchExact(searchTerm, limit) {}
166
+ return { results };
167
+ } catch (error) {
168
+ logError('pegasus-sdk', 'SearchService', 'searchChemicals', error);
169
+ throw error;
170
+ }
171
+ }
11
172
 
12
- async searchByCAS(casNumber, searchType) {}
173
+ /**
174
+ * Search for chemicals with prefix matching priority
175
+ * @param {string} searchTerm - Search term
176
+ * @param {number} limit - Maximum number of results (default: 10)
177
+ * @returns {Promise<Object>} Search results
178
+ */
179
+ async searchStartsWith(searchTerm, limit = 10) {
180
+ return this.searchChemicals(searchTerm, {
181
+ limit,
182
+ // Prioritize prefix matches over exact matches
183
+ casPrefix: 50,
184
+ casExact: 20,
185
+ namePrefix: 40,
186
+ nameExact: 15,
187
+ identifierPrefix: 30,
188
+ identifierExact: 10,
189
+ synonymPrefix: 35,
190
+ synonymExact: 10
191
+ });
192
+ }
13
193
 
14
- async searchByIdentifier(identifierValue, searchType) {}
194
+ /**
195
+ * Search for chemicals (alias for general search)
196
+ * @param {string} searchTerm - Search term
197
+ * @param {number} limit - Maximum number of results (default: 10)
198
+ * @returns {Promise<Object>} Search results
199
+ */
200
+ async searchContains(searchTerm, limit = 10) {
201
+ // Use default balanced weights for contains search
202
+ return this.searchChemicals(searchTerm, { limit });
203
+ }
15
204
 
16
- async searchBySynonym(synonymTerm, searchType) {}
205
+ /**
206
+ * Search for chemicals with exact matching priority
207
+ * @param {string} searchTerm - Search term
208
+ * @param {number} limit - Maximum number of results (default: 10)
209
+ * @returns {Promise<Object>} Search results
210
+ */
211
+ async searchExact(searchTerm, limit = 10) {
212
+ return this.searchChemicals(searchTerm, {
213
+ limit,
214
+ // Prioritize exact matches, minimize prefix matches
215
+ casExact: 100,
216
+ casPrefix: 1,
217
+ nameExact: 80,
218
+ namePrefix: 1,
219
+ identifierExact: 60,
220
+ identifierPrefix: 1,
221
+ synonymExact: 150,
222
+ synonymPrefix: 1
223
+ });
224
+ }
225
+
226
+ /**
227
+ * Search for chemicals by CAS number
228
+ * @param {string} casNumber - CAS number to search for
229
+ * @param {string} searchType - Search type: 'exact' or 'prefix' (default: 'exact')
230
+ * @returns {Promise<Object>} Search results
231
+ */
232
+ async searchByCAS(casNumber, searchType = 'exact') {
233
+ const isExact = searchType === 'exact';
234
+ return this.searchChemicals(casNumber, {
235
+ limit: 10,
236
+ // Heavily prioritize CAS field
237
+ casExact: isExact ? 200 : 50,
238
+ casPrefix: isExact ? 10 : 100,
239
+ nameExact: 5,
240
+ namePrefix: 1,
241
+ identifierExact: 5,
242
+ identifierPrefix: 1,
243
+ synonymExact: 5,
244
+ synonymPrefix: 1
245
+ });
246
+ }
247
+
248
+ /**
249
+ * Search for chemicals by identifier value
250
+ * @param {string} identifierValue - Identifier value to search for
251
+ * @param {string} searchType - Search type: 'exact' or 'prefix' (default: 'exact')
252
+ * @returns {Promise<Object>} Search results
253
+ */
254
+ async searchByIdentifier(identifierValue, searchType = 'exact') {
255
+ const isExact = searchType === 'exact';
256
+ return this.searchChemicals(identifierValue, {
257
+ limit: 10,
258
+ // Heavily prioritize identifier field
259
+ identifierExact: isExact ? 200 : 50,
260
+ identifierPrefix: isExact ? 10 : 100,
261
+ casExact: 10,
262
+ casPrefix: 5,
263
+ nameExact: 5,
264
+ namePrefix: 1,
265
+ synonymExact: 5,
266
+ synonymPrefix: 1
267
+ });
268
+ }
269
+
270
+ /**
271
+ * Search for chemicals by synonym
272
+ * @param {string} synonymTerm - Synonym term to search for
273
+ * @param {string} searchType - Search type: 'exact' or 'prefix' (default: 'exact')
274
+ * @returns {Promise<Object>} Search results
275
+ */
276
+ async searchBySynonym(synonymTerm, searchType = 'exact') {
277
+ const isExact = searchType === 'exact';
278
+ return this.searchChemicals(synonymTerm, {
279
+ limit: 10,
280
+ // Heavily prioritize synonym field
281
+ synonymExact: isExact ? 200 : 50,
282
+ synonymPrefix: isExact ? 10 : 100,
283
+ nameExact: 20,
284
+ namePrefix: 5,
285
+ casExact: 10,
286
+ casPrefix: 5,
287
+ identifierExact: 5,
288
+ identifierPrefix: 1
289
+ });
290
+ }
17
291
 
18
292
  async advancedSearch(queryBuilder) {}
19
293
 
@@ -28,6 +302,35 @@ class SearchService {
28
302
  async getSearchSuggestions(partialTerm, limit) {}
29
303
 
30
304
  async findSimilarChemicals(chemicalId, limit) {}
305
+
306
+ registerElasticsearchHandlers(elasticsearchService) {
307
+ const indexPatterns = this.connection.config.indexRoutes?.search || [/^(chemicals|substances|search)/];
308
+
309
+ indexPatterns.forEach(pattern => {
310
+ elasticsearchService.registerIndexRoute(pattern, {
311
+ search: async (params) => {
312
+ const query = params.body?.query;
313
+ const searchTerm = query?.match?.chemical_name ||
314
+ query?.term?.chemical_name ||
315
+ query?.query_string?.query ||
316
+ query?.match_all ? '*' : '';
317
+ const limit = params.body?.size || 10;
318
+
319
+ return await this.searchChemicals(searchTerm, { limit });
320
+ },
321
+
322
+ count: async (params) => {
323
+ const query = params.body?.query;
324
+ const searchTerm = query?.match?.chemical_name ||
325
+ query?.term?.chemical_name ||
326
+ query?.query_string?.query || '';
327
+
328
+ const results = await this.searchChemicals(searchTerm, { limit: 10000 });
329
+ return { count: results.results.length };
330
+ }
331
+ });
332
+ });
333
+ }
31
334
  }
32
335
 
33
336
  module.exports = SearchService;
package/lib/sync.js CHANGED
@@ -1,5 +1,7 @@
1
1
  class SyncService {
2
- constructor(connection) {}
2
+ constructor(connection) {
3
+ this.connection = connection;
4
+ }
3
5
 
4
6
  async syncBatch(batchSize) {}
5
7
 
package/lib/utils.js CHANGED
@@ -1,5 +1,7 @@
1
1
  class UtilsService {
2
- constructor(connection) {}
2
+ constructor(connection) {
3
+ this.connection = connection;
4
+ }
3
5
 
4
6
  async executeBatch(operations, batchSize, concurrency) {}
5
7
 
package/package.json CHANGED
@@ -1,23 +1,48 @@
1
1
  {
2
2
  "name": "@toxplanet/pegasus-sdk",
3
- "version": "1.0.0",
4
- "description": "SDK for migrating chemical data to Pegasus PostgreSQL + OpenSearch architecture",
3
+ "version": "1.0.2",
4
+ "description": "SDK for migrating chemical data to Pegasus PostgreSQL + OpenSearch architecture with Elasticsearch client compatibility",
5
5
  "main": "index.js",
6
+ "type": "commonjs",
6
7
  "scripts": {
8
+ "test": "vitest run",
9
+ "test:watch": "vitest",
10
+ "test:ui": "vitest --ui"
7
11
  },
8
12
  "keywords": [
13
+ "elasticsearch",
14
+ "opensearch",
15
+ "postgresql",
16
+ "aws",
17
+ "chemicals",
18
+ "database",
19
+ "search",
20
+ "sdk",
21
+ "pegasus",
22
+ "migration"
9
23
  ],
10
24
  "author": "Chemical Research Development Team",
11
25
  "license": "MIT",
12
26
  "dependencies": {
27
+ "@toxplanet/tphelper": "1.2.8",
13
28
  "pg": "^8.11.3",
29
+ "drizzle-orm": "^0.30.0",
14
30
  "@opensearch-project/opensearch": "^2.5.0",
15
- "@aws-sdk/client-opensearch-serverless": "^3.490.0",
16
31
  "@aws-sdk/client-secrets-manager": "^3.490.0",
17
- "@aws-sdk/credential-providers": "^3.490.0",
18
- "aws4fetch": "^1.0.18"
32
+ "@aws-sdk/credential-providers": "^3.490.0"
19
33
  },
20
34
  "engines": {
21
35
  "node": ">=18.0.0"
36
+ },
37
+ "files": [
38
+ "index.js",
39
+ "lib/",
40
+ "config/",
41
+ "README.md",
42
+ "ELASTICSEARCH_CLIENT.md",
43
+ "LICENSE"
44
+ ],
45
+ "devDependencies": {
46
+ "vitest": "^1.2.0"
22
47
  }
23
48
  }
package/env.example DELETED
@@ -1,3 +0,0 @@
1
- NODE_ENV=development
2
- AWS_REGION=us-east-1
3
- OPENSEARCH_ENDPOINT=https://your-collection.us-east-1.aoss.amazonaws.com
package/index.d.ts DELETED
@@ -1,215 +0,0 @@
1
- export interface PegasusConfig {
2
- environment?: string;
3
- region?: string;
4
- secretName?: string;
5
- openSearchEndpoint?: string;
6
- maxConnections?: number;
7
- minConnections?: number;
8
- idleTimeoutMillis?: number;
9
- connectionTimeoutMillis?: number;
10
- statementTimeout?: number;
11
- queryTimeout?: number;
12
- }
13
-
14
- export interface Chemical {
15
- chemical_id?: string;
16
- source_id: string;
17
- chemical_name: string;
18
- chemical_identifiers: Identifier[];
19
- chemical_synonyms: string[];
20
- chemical_categories: string[];
21
- chemical_meta: Record<string, any>;
22
- created_at?: Date;
23
- updated_at?: Date;
24
- }
25
-
26
- export interface Identifier {
27
- type: string;
28
- value: string;
29
- }
30
-
31
- export interface Document {
32
- document_id?: string;
33
- document_path: string;
34
- processed_at?: Date;
35
- cas_count?: number;
36
- }
37
-
38
- export interface OutboxEntry {
39
- outbox_id: number;
40
- chemical_id: string;
41
- operation: 'INSERT' | 'UPDATE' | 'DELETE';
42
- created_at: Date;
43
- processed_at?: Date;
44
- retry_count: number;
45
- last_error?: string;
46
- }
47
-
48
- export interface ConnectionStatus {
49
- postgres: {
50
- connected: boolean;
51
- timestamp?: Date;
52
- version?: string;
53
- poolSize?: number;
54
- idleConnections?: number;
55
- waitingRequests?: number;
56
- error?: string;
57
- };
58
- opensearch: {
59
- connected: boolean;
60
- version?: string;
61
- cluster?: string;
62
- error?: string;
63
- } | null;
64
- environment: string;
65
- region: string;
66
- }
67
-
68
- export declare class PegasusConnection {
69
- constructor(config?: PegasusConfig);
70
- getSecret(): Promise<any>;
71
- connect(): Promise<void>;
72
- disconnect(): Promise<void>;
73
- getPostgresClient(): any;
74
- getOpenSearchClient(): any;
75
- testConnection(): Promise<ConnectionStatus>;
76
- query(sql: string, params?: any[]): Promise<any>;
77
- getClient(): Promise<any>;
78
- transaction(callback: (client: any) => Promise<any>): Promise<any>;
79
- }
80
-
81
- export declare class ChemicalsService {
82
- constructor(connection: PegasusConnection);
83
- bulkIndexFielded(documents: any[]): Promise<void>;
84
- bulkIndexFulltext(documents: any[]): Promise<void>;
85
- bulkIndexSubstances(substances: any[]): Promise<void>;
86
- createChemical(chemical: Chemical): Promise<Chemical>;
87
- updateChemical(chemicalId: string, updates: Partial<Chemical>): Promise<Chemical>;
88
- deleteChemical(chemicalId: string): Promise<void>;
89
- deleteBySourceId(sourceId: string): Promise<void>;
90
- deleteCollection(collectionName: string): Promise<number>;
91
- updateCollectionProperty(collectionName: string, propertyPath: string, newValue: any): Promise<number>;
92
- bulkUpdateProperty(filter: any, propertyPath: string, newValue: any): Promise<number>;
93
- getChemicalById(chemicalId: string): Promise<Chemical>;
94
- getChemicalBySourceId(sourceId: string): Promise<Chemical>;
95
- getChemicalsByCAS(casNumber: string): Promise<Chemical[]>;
96
- getChemicalsByIdentifier(identifierType: string, identifierValue: string): Promise<Chemical[]>;
97
- countAll(): Promise<number>;
98
- countByCollection(collectionName: string): Promise<number>;
99
- countByIdentifier(identifierValue: string): Promise<number>;
100
- countByCAS(casNumber: string): Promise<number>;
101
- getTotalSynonymCount(): Promise<number>;
102
- getSynonymCount(synonymTerm: string): Promise<number>;
103
- convertIdentifier(fromIdentifier: string, toIdentifierType: string): Promise<any>;
104
- convertIdentifiersBatch(fromIdentifiers: string[], toIdentifierType: string): Promise<any[]>;
105
- searchByName(searchTerm: string, limit: number): Promise<Chemical[]>;
106
- searchBySynonym(synonymTerm: string, limit: number): Promise<Chemical[]>;
107
- findChemicalsWithoutDocuments(collectionName: string, searchTerm: string, pageSize: number): Promise<Chemical[]>;
108
- countChemicalsWithoutDocuments(collectionName: string): Promise<number>;
109
- }
110
-
111
- export declare class DocumentsService {
112
- constructor(connection: PegasusConnection);
113
- createDocument(documentPath: string, casNumbers: string[]): Promise<Document>;
114
- bulkCreateDocuments(documents: any[]): Promise<void>;
115
- updateDocument(documentId: string, updates: Partial<Document>): Promise<Document>;
116
- deleteDocument(documentId: string): Promise<void>;
117
- deleteDocumentByPath(documentPath: string): Promise<void>;
118
- getDocumentById(documentId: string): Promise<Document>;
119
- getDocumentByPath(documentPath: string): Promise<Document>;
120
- getDocumentsByCAS(casNumber: string): Promise<Document[]>;
121
- getCASByDocument(documentId: string): Promise<string[]>;
122
- getCASByDocumentPath(documentPath: string): Promise<string[]>;
123
- addCASToDocument(documentId: string, casNumber: string): Promise<void>;
124
- addCASToDocumentBatch(documentId: string, casNumbers: string[]): Promise<void>;
125
- removeCASFromDocument(documentId: string, casNumber: string): Promise<void>;
126
- findDocumentsWithMultipleCAS(casNumbers: string[], requireAll: boolean): Promise<Document[]>;
127
- countDocuments(): Promise<number>;
128
- countDocumentsByCAS(casNumber: string): Promise<number>;
129
- countUniqueCAS(): Promise<number>;
130
- getTopCASByDocumentCount(limit: number): Promise<any[]>;
131
- extractTextFromPDF(pdfBuffer: Buffer): Promise<string>;
132
- extractCASFromText(text: string): Promise<string[]>;
133
- processDocument(documentPath: string, documentData: any): Promise<Document>;
134
- }
135
-
136
- export declare class SearchService {
137
- constructor(connection: PegasusConnection);
138
- searchChemicals(searchTerm: string, searchType: string, limit: number, offset: number): Promise<any[]>;
139
- searchStartsWith(searchTerm: string, limit: number): Promise<any[]>;
140
- searchContains(searchTerm: string, limit: number): Promise<any[]>;
141
- searchExact(searchTerm: string, limit: number): Promise<any[]>;
142
- searchByCAS(casNumber: string, searchType: string): Promise<any[]>;
143
- searchByIdentifier(identifierValue: string, searchType: string): Promise<any[]>;
144
- searchBySynonym(synonymTerm: string, searchType: string): Promise<any[]>;
145
- advancedSearch(queryBuilder: any): Promise<any[]>;
146
- searchWithFilters(searchTerm: string, filters: any, limit: number): Promise<any[]>;
147
- searchByCollection(collectionName: string, searchTerm: string, limit: number): Promise<any[]>;
148
- aggregateByCategory(): Promise<any>;
149
- aggregateByIdentifierType(): Promise<any>;
150
- getSearchSuggestions(partialTerm: string, limit: number): Promise<string[]>;
151
- findSimilarChemicals(chemicalId: string, limit: number): Promise<any[]>;
152
- }
153
-
154
- export declare class SyncService {
155
- constructor(connection: PegasusConnection);
156
- syncBatch(batchSize: number): Promise<number>;
157
- syncAll(): Promise<number>;
158
- syncContinuous(intervalMs: number): Promise<void>;
159
- stopContinuousSync(): Promise<void>;
160
- getPendingCount(): Promise<number>;
161
- getOldestPending(): Promise<Date>;
162
- getSyncLag(): Promise<number>;
163
- getFailedEntries(minRetryCount: number): Promise<OutboxEntry[]>;
164
- retryFailed(outboxId: number): Promise<void>;
165
- retryAllFailed(): Promise<number>;
166
- markAsProcessed(outboxId: number): Promise<void>;
167
- deleteProcessedOlderThan(days: number): Promise<number>;
168
- cleanupOutbox(daysToKeep: number): Promise<number>;
169
- getSyncStats(timeWindowMinutes: number): Promise<any>;
170
- getSyncThroughput(): Promise<number>;
171
- verifySync(chemicalId: string): Promise<boolean>;
172
- forceResync(chemicalId: string): Promise<void>;
173
- getOutboxHealth(): Promise<any>;
174
- }
175
-
176
-
177
- export declare class UtilsService {
178
- constructor(connection: PegasusConnection);
179
- executeBatch(operations: any[], batchSize: number, concurrency: number): Promise<void>;
180
- withTransaction(callback: () => Promise<any>): Promise<any>;
181
- withRetry(operation: () => Promise<any>, maxRetries: number, backoffMs: number): Promise<any>;
182
- validateChemical(chemical: Chemical): boolean;
183
- validateDocument(document: Document): boolean;
184
- validateIdentifier(identifier: Identifier): boolean;
185
- validateCAS(casNumber: string): boolean;
186
- transformForOpenSearch(chemical: Chemical): any;
187
- transformFromElasticsearch(esDocument: any): Chemical;
188
- transformFromDynamoDB(dynamoItem: any): Chemical;
189
- buildOpenSearchQuery(searchTerm: string, searchType: string): any;
190
- buildPostgresFilter(filters: any): any;
191
- parseChemicalIdentifiers(identifiers: any): Identifier[];
192
- parseSynonyms(synonyms: any): string[];
193
- extractCASFromText(text: string): string[];
194
- sanitizeSearchTerm(term: string): string;
195
- generateSourceId(chemical: Chemical): string;
196
- calculateChecksum(data: any): string;
197
- formatError(error: Error): any;
198
- logOperation(operation: string, duration: number, metadata: any): void;
199
- getTimestamp(): Date;
200
- }
201
-
202
-
203
- export default class PegasusSDK {
204
- connection: PegasusConnection;
205
- chemicals: ChemicalsService;
206
- documents: DocumentsService;
207
- search: SearchService;
208
- sync: SyncService;
209
- utils: UtilsService;
210
-
211
- constructor(config: PegasusConfig);
212
- connect(): Promise<void>;
213
- disconnect(): Promise<void>;
214
- healthCheck(): Promise<any>;
215
- }