aparavi-client 1.0.9 → 1.0.10
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/aparavi-client-1.0.10.tgz +0 -0
- package/dist/cjs/client.js +638 -106
- package/dist/cjs/client.js.map +1 -1
- package/dist/cjs/schema/DocMetadata.js +1 -0
- package/dist/cjs/schema/DocMetadata.js.map +1 -1
- package/dist/cli/src/client.js +638 -106
- package/dist/cli/src/client.js.map +1 -1
- package/dist/cli/src/schema/DocMetadata.js +1 -0
- package/dist/cli/src/schema/DocMetadata.js.map +1 -1
- package/dist/esm/client.js +638 -106
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/schema/DocMetadata.js +1 -0
- package/dist/esm/schema/DocMetadata.js.map +1 -1
- package/dist/types/client.d.ts +425 -0
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/schema/DocMetadata.d.ts.map +1 -1
- package/dist/types/types/task.d.ts +49 -0
- package/dist/types/types/task.d.ts.map +1 -1
- package/package.json +4 -7
package/dist/cli/src/client.js
CHANGED
|
@@ -329,11 +329,6 @@ class AparaviClient extends DAPClient_1.DAPClient {
|
|
|
329
329
|
static _convertToWebSocketUri(uri) {
|
|
330
330
|
try {
|
|
331
331
|
const url = new URL(uri);
|
|
332
|
-
// If already a WebSocket URI, preserve it
|
|
333
|
-
if (url.protocol === 'wss:' || url.protocol === 'ws:') {
|
|
334
|
-
return `${url.protocol}//${url.host}`;
|
|
335
|
-
}
|
|
336
|
-
// Convert HTTP/HTTPS to WS/WSS
|
|
337
332
|
const wsScheme = url.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
338
333
|
return `${wsScheme}//${url.host}`;
|
|
339
334
|
}
|
|
@@ -490,6 +485,7 @@ class AparaviClient extends DAPClient_1.DAPClient {
|
|
|
490
485
|
* @param options.threads - Number of threads for execution (default: 1)
|
|
491
486
|
* @param options.useExisting - Use existing pipeline instance
|
|
492
487
|
* @param options.args - Command line arguments to pass to pipeline
|
|
488
|
+
* @param options.ttl - Time-to-live in seconds for idle pipelines (optional, server default if not provided; use 0 for no timeout)
|
|
493
489
|
*
|
|
494
490
|
* @returns Promise resolving to an object containing the task token and other metadata
|
|
495
491
|
* @throws Error if neither pipeline nor filepath is provided
|
|
@@ -510,7 +506,7 @@ class AparaviClient extends DAPClient_1.DAPClient {
|
|
|
510
506
|
* ```
|
|
511
507
|
*/
|
|
512
508
|
async use(options = {}) {
|
|
513
|
-
const { token, filepath, pipeline, source, threads, useExisting, args } = options;
|
|
509
|
+
const { token, filepath, pipeline, source, threads, useExisting, args, ttl } = options;
|
|
514
510
|
// Validate required parameters
|
|
515
511
|
if (!pipeline && !filepath) {
|
|
516
512
|
throw new Error('Pipeline configuration or file path is required and must be specified');
|
|
@@ -534,8 +530,6 @@ class AparaviClient extends DAPClient_1.DAPClient {
|
|
|
534
530
|
let processedConfig = JSON.parse(JSON.stringify(pipelineConfig));
|
|
535
531
|
// Perform environment variable substitution on the pipeline configuration
|
|
536
532
|
processedConfig = this.processEnvSubstitution(processedConfig);
|
|
537
|
-
// Sanitize webhook configs for remote servers (remove port parameter)
|
|
538
|
-
// processedConfig = this.sanitizePipelineForRemote(processedConfig);
|
|
539
533
|
// Override source if specified (after substitution)
|
|
540
534
|
if (source !== undefined) {
|
|
541
535
|
processedConfig.pipeline.source = source;
|
|
@@ -545,6 +539,10 @@ class AparaviClient extends DAPClient_1.DAPClient {
|
|
|
545
539
|
pipeline: processedConfig,
|
|
546
540
|
args: args || [],
|
|
547
541
|
};
|
|
542
|
+
// Add TTL if provided (server uses its default if not specified)
|
|
543
|
+
if (ttl !== undefined) {
|
|
544
|
+
arguments_.ttl = ttl;
|
|
545
|
+
}
|
|
548
546
|
// Add optional parameters if specified
|
|
549
547
|
if (token !== undefined) {
|
|
550
548
|
arguments_.token = token;
|
|
@@ -574,104 +572,6 @@ class AparaviClient extends DAPClient_1.DAPClient {
|
|
|
574
572
|
// Type assertion to ensure token is present
|
|
575
573
|
return responseBody;
|
|
576
574
|
}
|
|
577
|
-
// /**
|
|
578
|
-
// * Check if the client is connected to a remote server (not localhost).
|
|
579
|
-
// * @returns True if connecting to a remote server, False if localhost
|
|
580
|
-
// */
|
|
581
|
-
// private isRemoteServer(): boolean {
|
|
582
|
-
// try {
|
|
583
|
-
// const uri = this._uri || '';
|
|
584
|
-
// if (!uri) {
|
|
585
|
-
// return true; // Assume remote if URI not available
|
|
586
|
-
// }
|
|
587
|
-
// // Normalize URI - remove protocol and check hostname
|
|
588
|
-
// let uriLower = uri.toLowerCase();
|
|
589
|
-
// // Remove ws://, wss://, http://, https://
|
|
590
|
-
// uriLower = uriLower.replace(/^(ws|wss|http|https):\/\//, '');
|
|
591
|
-
// // Remove port if present
|
|
592
|
-
// uriLower = uriLower.replace(/:\d+/, '');
|
|
593
|
-
// // Remove path
|
|
594
|
-
// uriLower = uriLower.split('/')[0];
|
|
595
|
-
// // Check if it's localhost or local
|
|
596
|
-
// const localhostPatterns = ['localhost', '127.0.0.1', '::1', '0.0.0.0', 'local'];
|
|
597
|
-
// return !localhostPatterns.some(pattern => uriLower.includes(pattern));
|
|
598
|
-
// } catch {
|
|
599
|
-
// // If we can't determine, assume remote to be safe
|
|
600
|
-
// return true;
|
|
601
|
-
// }
|
|
602
|
-
// }
|
|
603
|
-
// /**
|
|
604
|
-
// * Remove port parameter from webhook config for remote servers.
|
|
605
|
-
// * @param config Webhook component configuration object
|
|
606
|
-
// * @returns Sanitized configuration object
|
|
607
|
-
// */
|
|
608
|
-
// private sanitizeWebhookConfig(config: any): any {
|
|
609
|
-
// if (!config || typeof config !== 'object') {
|
|
610
|
-
// return config;
|
|
611
|
-
// }
|
|
612
|
-
// // Check if this is a webhook component
|
|
613
|
-
// if (config.type === 'webhook' || String(config.provider || '').toLowerCase().includes('webhook')) {
|
|
614
|
-
// // Check parameters
|
|
615
|
-
// const parameters = config.parameters;
|
|
616
|
-
// if (parameters && typeof parameters === 'object' && 'port' in parameters) {
|
|
617
|
-
// // Remove port for remote servers
|
|
618
|
-
// if (this.isRemoteServer()) {
|
|
619
|
-
// // Create a copy to avoid modifying original
|
|
620
|
-
// const sanitized = JSON.parse(JSON.stringify(config));
|
|
621
|
-
// const { port, ...restParams } = sanitized.parameters;
|
|
622
|
-
// sanitized.parameters = restParams;
|
|
623
|
-
// this.debugMessage('Removed port parameter from webhook config for remote server');
|
|
624
|
-
// return sanitized;
|
|
625
|
-
// }
|
|
626
|
-
// }
|
|
627
|
-
// }
|
|
628
|
-
// return config;
|
|
629
|
-
// }
|
|
630
|
-
// /**
|
|
631
|
-
// * Recursively sanitize pipeline configuration for remote servers.
|
|
632
|
-
// * Removes port parameters from webhook components.
|
|
633
|
-
// * @param config Pipeline configuration object
|
|
634
|
-
// * @returns Sanitized pipeline configuration
|
|
635
|
-
// */
|
|
636
|
-
// private sanitizePipelineForRemote(config: any): any {
|
|
637
|
-
// if (!config || typeof config !== 'object') {
|
|
638
|
-
// return config;
|
|
639
|
-
// }
|
|
640
|
-
// // Create a deep copy to avoid modifying original
|
|
641
|
-
// const sanitized = JSON.parse(JSON.stringify(config));
|
|
642
|
-
// // Check if this is a pipeline config with components
|
|
643
|
-
// if (sanitized.pipeline) {
|
|
644
|
-
// const pipeline = sanitized.pipeline;
|
|
645
|
-
// if (pipeline.components && Array.isArray(pipeline.components)) {
|
|
646
|
-
// // Process each component
|
|
647
|
-
// for (let i = 0; i < pipeline.components.length; i++) {
|
|
648
|
-
// const component = pipeline.components[i];
|
|
649
|
-
// if (component && typeof component === 'object') {
|
|
650
|
-
// // Check if this is a webhook component by provider
|
|
651
|
-
// const provider = component.provider || '';
|
|
652
|
-
// if (provider === 'webhook' && component.config) {
|
|
653
|
-
// // Sanitize webhook configs
|
|
654
|
-
// pipeline.components[i].config = this.sanitizeWebhookConfig(component.config);
|
|
655
|
-
// }
|
|
656
|
-
// }
|
|
657
|
-
// }
|
|
658
|
-
// }
|
|
659
|
-
// }
|
|
660
|
-
// // Also check direct component arrays (for nested structures)
|
|
661
|
-
// if (sanitized.components && Array.isArray(sanitized.components)) {
|
|
662
|
-
// for (let i = 0; i < sanitized.components.length; i++) {
|
|
663
|
-
// const component = sanitized.components[i];
|
|
664
|
-
// if (component && typeof component === 'object') {
|
|
665
|
-
// // Check if this is a webhook component by provider
|
|
666
|
-
// const provider = component.provider || '';
|
|
667
|
-
// if (provider === 'webhook' && component.config) {
|
|
668
|
-
// component.config = this.sanitizeWebhookConfig(component.config);
|
|
669
|
-
// }
|
|
670
|
-
// }
|
|
671
|
-
// }
|
|
672
|
-
// }
|
|
673
|
-
// return sanitized;
|
|
674
|
-
// }
|
|
675
575
|
/**
|
|
676
576
|
* Terminate a running pipeline.
|
|
677
577
|
*/
|
|
@@ -1059,6 +959,638 @@ class AparaviClient extends DAPClient_1.DAPClient {
|
|
|
1059
959
|
}
|
|
1060
960
|
}
|
|
1061
961
|
// ============================================================================
|
|
962
|
+
// PROJECT STORAGE MANAGEMENT
|
|
963
|
+
// ============================================================================
|
|
964
|
+
/**
|
|
965
|
+
* Save or update a project pipeline.
|
|
966
|
+
*
|
|
967
|
+
* Stores a project pipeline configuration on the server. If the project
|
|
968
|
+
* already exists, it will be updated. Use expectedVersion to ensure
|
|
969
|
+
* you're updating the version you expect (prevents conflicts).
|
|
970
|
+
*
|
|
971
|
+
* @param options - Save project options
|
|
972
|
+
* @param options.projectId - Unique identifier for the project
|
|
973
|
+
* @param options.pipeline - Pipeline configuration object
|
|
974
|
+
* @param options.expectedVersion - Expected current version for atomic updates (optional)
|
|
975
|
+
* @returns Promise resolving to save result with success status, projectId, and new version
|
|
976
|
+
* @throws Error if save fails due to version mismatch, storage error, or invalid input
|
|
977
|
+
*
|
|
978
|
+
* @example
|
|
979
|
+
* ```typescript
|
|
980
|
+
* // Save a new project
|
|
981
|
+
* const result = await client.saveProject({
|
|
982
|
+
* projectId: 'proj-123',
|
|
983
|
+
* pipeline: {
|
|
984
|
+
* name: 'Data Processor',
|
|
985
|
+
* source: 'source_1',
|
|
986
|
+
* components: [...]
|
|
987
|
+
* }
|
|
988
|
+
* });
|
|
989
|
+
* console.log(`Saved version: ${result.version}`);
|
|
990
|
+
*
|
|
991
|
+
* // Update existing project with version check
|
|
992
|
+
* const existing = await client.getProject({ projectId: 'proj-123' });
|
|
993
|
+
* existing.pipeline.name = 'Updated Name';
|
|
994
|
+
* const updated = await client.saveProject({
|
|
995
|
+
* projectId: 'proj-123',
|
|
996
|
+
* pipeline: existing.pipeline,
|
|
997
|
+
* expectedVersion: existing.version
|
|
998
|
+
* });
|
|
999
|
+
* ```
|
|
1000
|
+
*/
|
|
1001
|
+
async saveProject(options) {
|
|
1002
|
+
const { projectId, pipeline, expectedVersion } = options;
|
|
1003
|
+
// Validate inputs
|
|
1004
|
+
if (!projectId) {
|
|
1005
|
+
throw new Error('projectId is required');
|
|
1006
|
+
}
|
|
1007
|
+
if (!pipeline || typeof pipeline !== 'object') {
|
|
1008
|
+
throw new Error('pipeline must be a non-empty object');
|
|
1009
|
+
}
|
|
1010
|
+
// Build request arguments
|
|
1011
|
+
const args = {
|
|
1012
|
+
subcommand: 'save_project',
|
|
1013
|
+
projectId,
|
|
1014
|
+
pipeline,
|
|
1015
|
+
};
|
|
1016
|
+
// Add optional version for atomic updates
|
|
1017
|
+
if (expectedVersion !== undefined) {
|
|
1018
|
+
args.expectedVersion = expectedVersion;
|
|
1019
|
+
}
|
|
1020
|
+
// Send request to server
|
|
1021
|
+
const request = this.buildRequest('apaext_store', { arguments: args });
|
|
1022
|
+
const response = await this.request(request);
|
|
1023
|
+
// Check for errors
|
|
1024
|
+
if (this.didFail(response)) {
|
|
1025
|
+
const errorMsg = response.message || 'Unknown error saving project';
|
|
1026
|
+
this.debugMessage(`Project save failed: ${errorMsg}`);
|
|
1027
|
+
throw new Error(errorMsg);
|
|
1028
|
+
}
|
|
1029
|
+
// Extract and return response
|
|
1030
|
+
this.debugMessage(`Project saved successfully: ${projectId}, version: ${response.body?.version}`);
|
|
1031
|
+
return response.body;
|
|
1032
|
+
}
|
|
1033
|
+
/**
|
|
1034
|
+
* Retrieve a project by its ID.
|
|
1035
|
+
*
|
|
1036
|
+
* Fetches the complete pipeline configuration and current version for
|
|
1037
|
+
* the specified project. Use this before updating to get the current
|
|
1038
|
+
* version for atomic updates.
|
|
1039
|
+
*
|
|
1040
|
+
* @param options - Get project options
|
|
1041
|
+
* @param options.projectId - Unique identifier of the project to retrieve
|
|
1042
|
+
* @returns Promise resolving to project data with success status, pipeline, and version
|
|
1043
|
+
* @throws Error if project doesn't exist or retrieval fails
|
|
1044
|
+
*
|
|
1045
|
+
* @example
|
|
1046
|
+
* ```typescript
|
|
1047
|
+
* // Get a project
|
|
1048
|
+
* try {
|
|
1049
|
+
* const project = await client.getProject({ projectId: 'proj-123' });
|
|
1050
|
+
* console.log(`Project: ${project.pipeline.name}`);
|
|
1051
|
+
* console.log(`Version: ${project.version}`);
|
|
1052
|
+
* } catch (error) {
|
|
1053
|
+
* if (error.message.includes('NOT_FOUND')) {
|
|
1054
|
+
* console.log("Project doesn't exist");
|
|
1055
|
+
* }
|
|
1056
|
+
* }
|
|
1057
|
+
*
|
|
1058
|
+
* // Before updating - get current version
|
|
1059
|
+
* const project = await client.getProject({ projectId: 'proj-123' });
|
|
1060
|
+
* project.pipeline.name = 'Updated';
|
|
1061
|
+
* await client.saveProject({
|
|
1062
|
+
* projectId: 'proj-123',
|
|
1063
|
+
* pipeline: project.pipeline,
|
|
1064
|
+
* expectedVersion: project.version
|
|
1065
|
+
* });
|
|
1066
|
+
* ```
|
|
1067
|
+
*/
|
|
1068
|
+
async getProject(options) {
|
|
1069
|
+
const { projectId } = options;
|
|
1070
|
+
// Validate inputs
|
|
1071
|
+
if (!projectId) {
|
|
1072
|
+
throw new Error('projectId is required');
|
|
1073
|
+
}
|
|
1074
|
+
// Build request
|
|
1075
|
+
const args = {
|
|
1076
|
+
subcommand: 'get_project',
|
|
1077
|
+
projectId,
|
|
1078
|
+
};
|
|
1079
|
+
// Send request to server
|
|
1080
|
+
const request = this.buildRequest('apaext_store', { arguments: args });
|
|
1081
|
+
const response = await this.request(request);
|
|
1082
|
+
// Check for errors
|
|
1083
|
+
if (this.didFail(response)) {
|
|
1084
|
+
const errorMsg = response.message || 'Unknown error retrieving project';
|
|
1085
|
+
this.debugMessage(`Project retrieval failed: ${errorMsg}`);
|
|
1086
|
+
throw new Error(errorMsg);
|
|
1087
|
+
}
|
|
1088
|
+
// Extract and return response
|
|
1089
|
+
this.debugMessage(`Project retrieved successfully: ${projectId}`);
|
|
1090
|
+
return response.body;
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Delete a project by its ID.
|
|
1094
|
+
*
|
|
1095
|
+
* Permanently removes a project from storage. Optionally verify the
|
|
1096
|
+
* version before deletion to ensure you're deleting the version you
|
|
1097
|
+
* expect (prevents accidental deletion of modified projects).
|
|
1098
|
+
*
|
|
1099
|
+
* @param options - Delete project options
|
|
1100
|
+
* @param options.projectId - Unique identifier of the project to delete
|
|
1101
|
+
* @param options.expectedVersion - Expected current version for atomic deletion (required)
|
|
1102
|
+
* @returns Promise resolving to deletion result with success status and message
|
|
1103
|
+
* @throws Error if project doesn't exist, version mismatch, or deletion fails
|
|
1104
|
+
*
|
|
1105
|
+
* @example
|
|
1106
|
+
* ```typescript
|
|
1107
|
+
* // Safe deletion with version check
|
|
1108
|
+
* const project = await client.getProject({ projectId: 'proj-123' });
|
|
1109
|
+
* try {
|
|
1110
|
+
* const result = await client.deleteProject({
|
|
1111
|
+
* projectId: 'proj-123',
|
|
1112
|
+
* expectedVersion: project.version
|
|
1113
|
+
* });
|
|
1114
|
+
* console.log('Project deleted successfully');
|
|
1115
|
+
* } catch (error) {
|
|
1116
|
+
* if (error.message.includes('CONFLICT')) {
|
|
1117
|
+
* console.log('Project was modified, deletion cancelled');
|
|
1118
|
+
* }
|
|
1119
|
+
* }
|
|
1120
|
+
* ```
|
|
1121
|
+
*/
|
|
1122
|
+
async deleteProject(options) {
|
|
1123
|
+
const { projectId, expectedVersion } = options;
|
|
1124
|
+
// Validate inputs
|
|
1125
|
+
if (!projectId) {
|
|
1126
|
+
throw new Error('projectId is required');
|
|
1127
|
+
}
|
|
1128
|
+
// Build request
|
|
1129
|
+
const args = {
|
|
1130
|
+
subcommand: 'delete_project',
|
|
1131
|
+
projectId,
|
|
1132
|
+
};
|
|
1133
|
+
// Add optional version for atomic deletion
|
|
1134
|
+
if (expectedVersion !== undefined) {
|
|
1135
|
+
args.expectedVersion = expectedVersion;
|
|
1136
|
+
}
|
|
1137
|
+
// Send request to server
|
|
1138
|
+
const request = this.buildRequest('apaext_store', { arguments: args });
|
|
1139
|
+
const response = await this.request(request);
|
|
1140
|
+
// Check for errors
|
|
1141
|
+
if (this.didFail(response)) {
|
|
1142
|
+
const errorMsg = response.message || 'Unknown error deleting project';
|
|
1143
|
+
this.debugMessage(`Project deletion failed: ${errorMsg}`);
|
|
1144
|
+
throw new Error(errorMsg);
|
|
1145
|
+
}
|
|
1146
|
+
// Extract and return response
|
|
1147
|
+
this.debugMessage(`Project deleted successfully: ${projectId}`);
|
|
1148
|
+
return response.body;
|
|
1149
|
+
}
|
|
1150
|
+
/**
|
|
1151
|
+
* List all projects for the current user.
|
|
1152
|
+
*
|
|
1153
|
+
* Retrieves a summary of all projects stored for the authenticated user.
|
|
1154
|
+
* Each project summary includes the ID, name, list of data sources, and total component count.
|
|
1155
|
+
*
|
|
1156
|
+
* @returns Promise resolving to list result with success status, projects array, and count
|
|
1157
|
+
* @throws Error if retrieval fails
|
|
1158
|
+
*
|
|
1159
|
+
* @example
|
|
1160
|
+
* ```typescript
|
|
1161
|
+
* // List all projects
|
|
1162
|
+
* const result = await client.getAllProjects();
|
|
1163
|
+
* console.log(`Found ${result.count} projects:`);
|
|
1164
|
+
* for (const project of result.projects) {
|
|
1165
|
+
* console.log(`- ${project.id}: ${project.name} (${project.totalComponents} components)`);
|
|
1166
|
+
* for (const source of project.sources) {
|
|
1167
|
+
* console.log(` * ${source.name} (${source.provider})`);
|
|
1168
|
+
* }
|
|
1169
|
+
* }
|
|
1170
|
+
*
|
|
1171
|
+
* // Find specific project
|
|
1172
|
+
* const result = await client.getAllProjects();
|
|
1173
|
+
* const myProject = result.projects.find(p => p.id === 'proj-123');
|
|
1174
|
+
* ```
|
|
1175
|
+
*/
|
|
1176
|
+
async getAllProjects() {
|
|
1177
|
+
// Build request
|
|
1178
|
+
const args = {
|
|
1179
|
+
subcommand: 'get_all_projects',
|
|
1180
|
+
};
|
|
1181
|
+
// Send request to server
|
|
1182
|
+
const request = this.buildRequest('apaext_store', { arguments: args });
|
|
1183
|
+
const response = await this.request(request);
|
|
1184
|
+
// Check for errors
|
|
1185
|
+
if (this.didFail(response)) {
|
|
1186
|
+
const errorMsg = response.message || 'Unknown error listing projects';
|
|
1187
|
+
this.debugMessage(`Project list retrieval failed: ${errorMsg}`);
|
|
1188
|
+
throw new Error(errorMsg);
|
|
1189
|
+
}
|
|
1190
|
+
// Extract and return response
|
|
1191
|
+
const projectCount = response.body?.count || 0;
|
|
1192
|
+
this.debugMessage(`Projects retrieved successfully: ${projectCount} projects`);
|
|
1193
|
+
return response.body;
|
|
1194
|
+
}
|
|
1195
|
+
// ============================================================================
|
|
1196
|
+
// TEMPLATE STORAGE MANAGEMENT (System-wide templates)
|
|
1197
|
+
// ============================================================================
|
|
1198
|
+
/**
|
|
1199
|
+
* Save or update a template pipeline.
|
|
1200
|
+
*
|
|
1201
|
+
* Stores a template pipeline configuration on the server. Templates are system-wide
|
|
1202
|
+
* and accessible to all users. If the template already exists, it will be updated.
|
|
1203
|
+
* Use expectedVersion to ensure you're updating the version you expect.
|
|
1204
|
+
*
|
|
1205
|
+
* @param options - Save template options
|
|
1206
|
+
* @param options.templateId - Unique identifier for the template
|
|
1207
|
+
* @param options.pipeline - Pipeline configuration object
|
|
1208
|
+
* @param options.expectedVersion - Expected current version for atomic updates (optional)
|
|
1209
|
+
* @returns Promise resolving to save result with success status, templateId, and new version
|
|
1210
|
+
* @throws Error if save fails due to version mismatch, storage error, or invalid input
|
|
1211
|
+
*
|
|
1212
|
+
* @example
|
|
1213
|
+
* ```typescript
|
|
1214
|
+
* // Save a new template
|
|
1215
|
+
* const result = await client.saveTemplate({
|
|
1216
|
+
* templateId: 'tmpl-123',
|
|
1217
|
+
* pipeline: {
|
|
1218
|
+
* source: 'source_1',
|
|
1219
|
+
* pipeline: {
|
|
1220
|
+
* name: 'Data Processor Template',
|
|
1221
|
+
* components: [...]
|
|
1222
|
+
* }
|
|
1223
|
+
* }
|
|
1224
|
+
* });
|
|
1225
|
+
* console.log(`Saved version: ${result.version}`);
|
|
1226
|
+
* ```
|
|
1227
|
+
*/
|
|
1228
|
+
async saveTemplate(options) {
|
|
1229
|
+
const { templateId, pipeline, expectedVersion } = options;
|
|
1230
|
+
// Validate inputs
|
|
1231
|
+
if (!templateId) {
|
|
1232
|
+
throw new Error('templateId is required');
|
|
1233
|
+
}
|
|
1234
|
+
if (!pipeline || typeof pipeline !== 'object') {
|
|
1235
|
+
throw new Error('pipeline must be a non-empty object');
|
|
1236
|
+
}
|
|
1237
|
+
// Build request arguments
|
|
1238
|
+
const args = {
|
|
1239
|
+
subcommand: 'save_template',
|
|
1240
|
+
templateId,
|
|
1241
|
+
pipeline,
|
|
1242
|
+
};
|
|
1243
|
+
// Add optional version for atomic updates
|
|
1244
|
+
if (expectedVersion !== undefined) {
|
|
1245
|
+
args.expectedVersion = expectedVersion;
|
|
1246
|
+
}
|
|
1247
|
+
// Send request to server
|
|
1248
|
+
const request = this.buildRequest('apaext_store', { arguments: args });
|
|
1249
|
+
const response = await this.request(request);
|
|
1250
|
+
// Check for errors
|
|
1251
|
+
if (this.didFail(response)) {
|
|
1252
|
+
const errorMsg = response.message || 'Unknown error saving template';
|
|
1253
|
+
this.debugMessage(`Template save failed: ${errorMsg}`);
|
|
1254
|
+
throw new Error(errorMsg);
|
|
1255
|
+
}
|
|
1256
|
+
// Extract and return response
|
|
1257
|
+
this.debugMessage(`Template saved successfully: ${templateId}, version: ${response.body?.version}`);
|
|
1258
|
+
return response.body;
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Retrieve a template by its ID.
|
|
1262
|
+
*
|
|
1263
|
+
* Fetches the complete pipeline configuration and current version for
|
|
1264
|
+
* the specified template.
|
|
1265
|
+
*
|
|
1266
|
+
* @param options - Get template options
|
|
1267
|
+
* @param options.templateId - Unique identifier of the template to retrieve
|
|
1268
|
+
* @returns Promise resolving to template data with success status, pipeline, and version
|
|
1269
|
+
* @throws Error if template doesn't exist or retrieval fails
|
|
1270
|
+
*
|
|
1271
|
+
* @example
|
|
1272
|
+
* ```typescript
|
|
1273
|
+
* try {
|
|
1274
|
+
* const template = await client.getTemplate({ templateId: 'tmpl-123' });
|
|
1275
|
+
* console.log(`Template: ${template.pipeline.pipeline.name}`);
|
|
1276
|
+
* console.log(`Version: ${template.version}`);
|
|
1277
|
+
* } catch (error) {
|
|
1278
|
+
* if (error.message.includes('NOT_FOUND')) {
|
|
1279
|
+
* console.log("Template doesn't exist");
|
|
1280
|
+
* }
|
|
1281
|
+
* }
|
|
1282
|
+
* ```
|
|
1283
|
+
*/
|
|
1284
|
+
async getTemplate(options) {
|
|
1285
|
+
const { templateId } = options;
|
|
1286
|
+
// Validate inputs
|
|
1287
|
+
if (!templateId) {
|
|
1288
|
+
throw new Error('templateId is required');
|
|
1289
|
+
}
|
|
1290
|
+
// Build request
|
|
1291
|
+
const args = {
|
|
1292
|
+
subcommand: 'get_template',
|
|
1293
|
+
templateId,
|
|
1294
|
+
};
|
|
1295
|
+
// Send request to server
|
|
1296
|
+
const request = this.buildRequest('apaext_store', { arguments: args });
|
|
1297
|
+
const response = await this.request(request);
|
|
1298
|
+
// Check for errors
|
|
1299
|
+
if (this.didFail(response)) {
|
|
1300
|
+
const errorMsg = response.message || 'Unknown error retrieving template';
|
|
1301
|
+
this.debugMessage(`Template retrieval failed: ${errorMsg}`);
|
|
1302
|
+
throw new Error(errorMsg);
|
|
1303
|
+
}
|
|
1304
|
+
// Extract and return response
|
|
1305
|
+
this.debugMessage(`Template retrieved successfully: ${templateId}`);
|
|
1306
|
+
return response.body;
|
|
1307
|
+
}
|
|
1308
|
+
/**
|
|
1309
|
+
* Delete a template by its ID.
|
|
1310
|
+
*
|
|
1311
|
+
* Permanently removes a template from storage. Optionally verify the
|
|
1312
|
+
* version before deletion to ensure you're deleting the version you expect.
|
|
1313
|
+
*
|
|
1314
|
+
* @param options - Delete template options
|
|
1315
|
+
* @param options.templateId - Unique identifier of the template to delete
|
|
1316
|
+
* @param options.expectedVersion - Expected current version for atomic deletion (optional)
|
|
1317
|
+
* @returns Promise resolving to deletion result with success status and message
|
|
1318
|
+
* @throws Error if template doesn't exist, version mismatch, or deletion fails
|
|
1319
|
+
*
|
|
1320
|
+
* @example
|
|
1321
|
+
* ```typescript
|
|
1322
|
+
* // Safe deletion with version check
|
|
1323
|
+
* const template = await client.getTemplate({ templateId: 'tmpl-123' });
|
|
1324
|
+
* try {
|
|
1325
|
+
* const result = await client.deleteTemplate({
|
|
1326
|
+
* templateId: 'tmpl-123',
|
|
1327
|
+
* expectedVersion: template.version
|
|
1328
|
+
* });
|
|
1329
|
+
* console.log('Template deleted successfully');
|
|
1330
|
+
* } catch (error) {
|
|
1331
|
+
* if (error.message.includes('CONFLICT')) {
|
|
1332
|
+
* console.log('Template was modified, deletion cancelled');
|
|
1333
|
+
* }
|
|
1334
|
+
* }
|
|
1335
|
+
* ```
|
|
1336
|
+
*/
|
|
1337
|
+
async deleteTemplate(options) {
|
|
1338
|
+
const { templateId, expectedVersion } = options;
|
|
1339
|
+
// Validate inputs
|
|
1340
|
+
if (!templateId) {
|
|
1341
|
+
throw new Error('templateId is required');
|
|
1342
|
+
}
|
|
1343
|
+
// Build request
|
|
1344
|
+
const args = {
|
|
1345
|
+
subcommand: 'delete_template',
|
|
1346
|
+
templateId,
|
|
1347
|
+
};
|
|
1348
|
+
// Add optional version for atomic deletion
|
|
1349
|
+
if (expectedVersion !== undefined) {
|
|
1350
|
+
args.expectedVersion = expectedVersion;
|
|
1351
|
+
}
|
|
1352
|
+
// Send request to server
|
|
1353
|
+
const request = this.buildRequest('apaext_store', { arguments: args });
|
|
1354
|
+
const response = await this.request(request);
|
|
1355
|
+
// Check for errors
|
|
1356
|
+
if (this.didFail(response)) {
|
|
1357
|
+
const errorMsg = response.message || 'Unknown error deleting template';
|
|
1358
|
+
this.debugMessage(`Template deletion failed: ${errorMsg}`);
|
|
1359
|
+
throw new Error(errorMsg);
|
|
1360
|
+
}
|
|
1361
|
+
// Extract and return response
|
|
1362
|
+
this.debugMessage(`Template deleted successfully: ${templateId}`);
|
|
1363
|
+
return response.body;
|
|
1364
|
+
}
|
|
1365
|
+
/**
|
|
1366
|
+
* List all templates.
|
|
1367
|
+
*
|
|
1368
|
+
* Retrieves a summary of all templates stored in the system.
|
|
1369
|
+
* Each template summary includes the ID, name, list of data sources, and total component count.
|
|
1370
|
+
*
|
|
1371
|
+
* @returns Promise resolving to list result with success status, templates array, and count
|
|
1372
|
+
* @throws Error if retrieval fails
|
|
1373
|
+
*
|
|
1374
|
+
* @example
|
|
1375
|
+
* ```typescript
|
|
1376
|
+
* // List all templates
|
|
1377
|
+
* const result = await client.getAllTemplates();
|
|
1378
|
+
* console.log(`Found ${result.count} templates:`);
|
|
1379
|
+
* for (const template of result.templates) {
|
|
1380
|
+
* console.log(`- ${template.id}: ${template.name} (${template.totalComponents} components)`);
|
|
1381
|
+
* for (const source of template.sources) {
|
|
1382
|
+
* console.log(` * ${source.name} (${source.provider})`);
|
|
1383
|
+
* }
|
|
1384
|
+
* }
|
|
1385
|
+
* ```
|
|
1386
|
+
*/
|
|
1387
|
+
async getAllTemplates() {
|
|
1388
|
+
// Build request
|
|
1389
|
+
const args = {
|
|
1390
|
+
subcommand: 'get_all_templates',
|
|
1391
|
+
};
|
|
1392
|
+
// Send request to server
|
|
1393
|
+
const request = this.buildRequest('apaext_store', { arguments: args });
|
|
1394
|
+
const response = await this.request(request);
|
|
1395
|
+
// Check for errors
|
|
1396
|
+
if (this.didFail(response)) {
|
|
1397
|
+
const errorMsg = response.message || 'Unknown error listing templates';
|
|
1398
|
+
this.debugMessage(`Template list retrieval failed: ${errorMsg}`);
|
|
1399
|
+
throw new Error(errorMsg);
|
|
1400
|
+
}
|
|
1401
|
+
// Extract and return response
|
|
1402
|
+
const templateCount = response.body?.count || 0;
|
|
1403
|
+
this.debugMessage(`Templates retrieved successfully: ${templateCount} templates`);
|
|
1404
|
+
return response.body;
|
|
1405
|
+
}
|
|
1406
|
+
// ============================================================================
|
|
1407
|
+
// LOG STORAGE MANAGEMENT (Per-project log files for historical tracking)
|
|
1408
|
+
// ============================================================================
|
|
1409
|
+
/**
|
|
1410
|
+
* Save a log file for a source run.
|
|
1411
|
+
*
|
|
1412
|
+
* Creates or overwrites a log file in the project's log directory.
|
|
1413
|
+
* The filename is constructed as <source>-<startTime>.log where startTime
|
|
1414
|
+
* is extracted from contents.body.startTime.
|
|
1415
|
+
*
|
|
1416
|
+
* @param options - Save log options
|
|
1417
|
+
* @param options.projectId - Project ID
|
|
1418
|
+
* @param options.source - Name of the source
|
|
1419
|
+
* @param options.contents - Log contents object containing body.startTime
|
|
1420
|
+
* @returns Promise resolving to save result with success status and filename
|
|
1421
|
+
* @throws Error if save fails
|
|
1422
|
+
*
|
|
1423
|
+
* @example
|
|
1424
|
+
* ```typescript
|
|
1425
|
+
* const logContents = {
|
|
1426
|
+
* type: 'event',
|
|
1427
|
+
* event: 'apaevt_status_update',
|
|
1428
|
+
* body: {
|
|
1429
|
+
* source: 'source_1',
|
|
1430
|
+
* startTime: 1764337626.6564875,
|
|
1431
|
+
* status: 'Completed',
|
|
1432
|
+
* completed: true,
|
|
1433
|
+
* totalCount: 100,
|
|
1434
|
+
* completedCount: 100
|
|
1435
|
+
* }
|
|
1436
|
+
* };
|
|
1437
|
+
* const result = await client.saveLog({
|
|
1438
|
+
* projectId: 'proj-123',
|
|
1439
|
+
* source: 'source_1',
|
|
1440
|
+
* contents: logContents
|
|
1441
|
+
* });
|
|
1442
|
+
* console.log(`Saved: ${result.filename}`);
|
|
1443
|
+
* ```
|
|
1444
|
+
*/
|
|
1445
|
+
async saveLog(options) {
|
|
1446
|
+
const { projectId, source, contents } = options;
|
|
1447
|
+
// Validate inputs
|
|
1448
|
+
if (!projectId) {
|
|
1449
|
+
throw new Error('projectId is required');
|
|
1450
|
+
}
|
|
1451
|
+
if (!source) {
|
|
1452
|
+
throw new Error('source is required');
|
|
1453
|
+
}
|
|
1454
|
+
if (!contents || typeof contents !== 'object') {
|
|
1455
|
+
throw new Error('contents must be a non-empty object');
|
|
1456
|
+
}
|
|
1457
|
+
// Build request arguments
|
|
1458
|
+
const args = {
|
|
1459
|
+
subcommand: 'save_log',
|
|
1460
|
+
projectId,
|
|
1461
|
+
source,
|
|
1462
|
+
contents,
|
|
1463
|
+
};
|
|
1464
|
+
// Send request to server
|
|
1465
|
+
const request = this.buildRequest('apaext_store', { arguments: args });
|
|
1466
|
+
const response = await this.request(request);
|
|
1467
|
+
// Check for errors
|
|
1468
|
+
if (this.didFail(response)) {
|
|
1469
|
+
const errorMsg = response.message || 'Unknown error saving log';
|
|
1470
|
+
this.debugMessage(`Log save failed: ${errorMsg}`);
|
|
1471
|
+
throw new Error(errorMsg);
|
|
1472
|
+
}
|
|
1473
|
+
// Extract and return response
|
|
1474
|
+
this.debugMessage(`Log saved successfully: ${response.body?.filename}`);
|
|
1475
|
+
return response.body;
|
|
1476
|
+
}
|
|
1477
|
+
/**
|
|
1478
|
+
* Get a log file by source name and start time.
|
|
1479
|
+
*
|
|
1480
|
+
* @param options - Get log options
|
|
1481
|
+
* @param options.projectId - Project ID
|
|
1482
|
+
* @param options.source - Name of the source
|
|
1483
|
+
* @param options.startTime - Start time of the run
|
|
1484
|
+
* @returns Promise resolving to log data with success status and contents
|
|
1485
|
+
* @throws Error if log not found or retrieval fails
|
|
1486
|
+
*
|
|
1487
|
+
* @example
|
|
1488
|
+
* ```typescript
|
|
1489
|
+
* const log = await client.getLog({
|
|
1490
|
+
* projectId: 'proj-123',
|
|
1491
|
+
* source: 'source_1',
|
|
1492
|
+
* startTime: 1764337626.6564875
|
|
1493
|
+
* });
|
|
1494
|
+
* console.log(`Status: ${log.contents.body.status}`);
|
|
1495
|
+
* ```
|
|
1496
|
+
*/
|
|
1497
|
+
async getLog(options) {
|
|
1498
|
+
const { projectId, source, startTime } = options;
|
|
1499
|
+
// Validate inputs
|
|
1500
|
+
if (!projectId) {
|
|
1501
|
+
throw new Error('projectId is required');
|
|
1502
|
+
}
|
|
1503
|
+
if (!source) {
|
|
1504
|
+
throw new Error('source is required');
|
|
1505
|
+
}
|
|
1506
|
+
if (startTime === undefined || startTime === null) {
|
|
1507
|
+
throw new Error('startTime is required');
|
|
1508
|
+
}
|
|
1509
|
+
// Build request
|
|
1510
|
+
const args = {
|
|
1511
|
+
subcommand: 'get_log',
|
|
1512
|
+
projectId,
|
|
1513
|
+
source,
|
|
1514
|
+
startTime,
|
|
1515
|
+
};
|
|
1516
|
+
// Send request to server
|
|
1517
|
+
const request = this.buildRequest('apaext_store', { arguments: args });
|
|
1518
|
+
const response = await this.request(request);
|
|
1519
|
+
// Check for errors
|
|
1520
|
+
if (this.didFail(response)) {
|
|
1521
|
+
const errorMsg = response.message || 'Unknown error retrieving log';
|
|
1522
|
+
this.debugMessage(`Log retrieval failed: ${errorMsg}`);
|
|
1523
|
+
throw new Error(errorMsg);
|
|
1524
|
+
}
|
|
1525
|
+
// Extract and return response
|
|
1526
|
+
this.debugMessage(`Log retrieved successfully: ${projectId}/${source}`);
|
|
1527
|
+
return response.body;
|
|
1528
|
+
}
|
|
1529
|
+
/**
|
|
1530
|
+
* List log files for a project.
|
|
1531
|
+
*
|
|
1532
|
+
* @param options - List logs options
|
|
1533
|
+
* @param options.projectId - Project ID
|
|
1534
|
+
* @param options.source - Optional source name to filter logs (filters files starting with '<source>-')
|
|
1535
|
+
* @param options.page - Page number (0-indexed). If negative or undefined, defaults to 0. Page size is 100.
|
|
1536
|
+
* @returns Promise resolving to list result with success status, logs array, counts, and pagination info
|
|
1537
|
+
* @throws Error if retrieval fails
|
|
1538
|
+
*
|
|
1539
|
+
* @example
|
|
1540
|
+
* ```typescript
|
|
1541
|
+
* // List all logs
|
|
1542
|
+
* const result = await client.listLogs({ projectId: 'proj-123' });
|
|
1543
|
+
* console.log(`Found ${result.total_count} logs`);
|
|
1544
|
+
* for (const log of result.logs) {
|
|
1545
|
+
* console.log(` - ${log}`);
|
|
1546
|
+
* }
|
|
1547
|
+
*
|
|
1548
|
+
* // Filter by source
|
|
1549
|
+
* const filtered = await client.listLogs({
|
|
1550
|
+
* projectId: 'proj-123',
|
|
1551
|
+
* source: 'source_1'
|
|
1552
|
+
* });
|
|
1553
|
+
*
|
|
1554
|
+
* // With pagination
|
|
1555
|
+
* const page2 = await client.listLogs({
|
|
1556
|
+
* projectId: 'proj-123',
|
|
1557
|
+
* page: 1
|
|
1558
|
+
* });
|
|
1559
|
+
* ```
|
|
1560
|
+
*/
|
|
1561
|
+
async listLogs(options) {
|
|
1562
|
+
const { projectId, source, page } = options;
|
|
1563
|
+
// Validate inputs
|
|
1564
|
+
if (!projectId) {
|
|
1565
|
+
throw new Error('projectId is required');
|
|
1566
|
+
}
|
|
1567
|
+
// Build request
|
|
1568
|
+
const args = {
|
|
1569
|
+
subcommand: 'list_logs',
|
|
1570
|
+
projectId,
|
|
1571
|
+
};
|
|
1572
|
+
// Add optional parameters
|
|
1573
|
+
if (source !== undefined) {
|
|
1574
|
+
args.source = source;
|
|
1575
|
+
}
|
|
1576
|
+
if (page !== undefined) {
|
|
1577
|
+
args.page = page;
|
|
1578
|
+
}
|
|
1579
|
+
// Send request to server
|
|
1580
|
+
const request = this.buildRequest('apaext_store', { arguments: args });
|
|
1581
|
+
const response = await this.request(request);
|
|
1582
|
+
// Check for errors
|
|
1583
|
+
if (this.didFail(response)) {
|
|
1584
|
+
const errorMsg = response.message || 'Unknown error listing logs';
|
|
1585
|
+
this.debugMessage(`Log list retrieval failed: ${errorMsg}`);
|
|
1586
|
+
throw new Error(errorMsg);
|
|
1587
|
+
}
|
|
1588
|
+
// Extract and return response
|
|
1589
|
+
const logCount = response.body?.total_count || 0;
|
|
1590
|
+
this.debugMessage(`Logs retrieved successfully: ${logCount} logs`);
|
|
1591
|
+
return response.body;
|
|
1592
|
+
}
|
|
1593
|
+
// ============================================================================
|
|
1062
1594
|
// CONTEXT MANAGER SUPPORT - Python-style async context manager
|
|
1063
1595
|
// ============================================================================
|
|
1064
1596
|
/**
|