@helix-tools/sdk-typescript 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +23 -0
- package/dist/consumer.d.ts +226 -0
- package/dist/consumer.d.ts.map +1 -0
- package/dist/consumer.js +560 -0
- package/dist/consumer.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/producer.d.ts +160 -0
- package/dist/producer.d.ts.map +1 -0
- package/dist/producer.js +491 -0
- package/dist/producer.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helix Connect Platform Producer SDK
|
|
3
|
+
* For data producers who want to upload and manage datasets
|
|
4
|
+
*/
|
|
5
|
+
export interface HelixProducerConfig {
|
|
6
|
+
awsAccessKeyId: string;
|
|
7
|
+
awsSecretAccessKey: string;
|
|
8
|
+
customerId: string;
|
|
9
|
+
apiEndpoint?: string;
|
|
10
|
+
region?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Options for uploading a dataset.
|
|
14
|
+
*
|
|
15
|
+
* Security and Performance Defaults (v2.0+):
|
|
16
|
+
* - encrypt: true (KMS envelope encryption enabled by default)
|
|
17
|
+
* - compress: true (gzip compression enabled by default)
|
|
18
|
+
* - compressionLevel: 6 (balanced speed/size ratio)
|
|
19
|
+
*
|
|
20
|
+
* To disable encryption or compression, explicitly set to false:
|
|
21
|
+
* { ...options, encrypt: false, compress: false }
|
|
22
|
+
*/
|
|
23
|
+
export interface UploadOptions {
|
|
24
|
+
/** Name for the dataset (required) */
|
|
25
|
+
datasetName: string;
|
|
26
|
+
/** Description of the dataset */
|
|
27
|
+
description?: string;
|
|
28
|
+
/** Dataset category (default: "general") */
|
|
29
|
+
category?: string;
|
|
30
|
+
/** How often data is updated (default: "daily") */
|
|
31
|
+
dataFreshness?: string;
|
|
32
|
+
/** Additional custom metadata */
|
|
33
|
+
metadata?: Record<string, any>;
|
|
34
|
+
/** Enable KMS encryption (default: true for security) */
|
|
35
|
+
encrypt?: boolean;
|
|
36
|
+
/** Enable gzip compression (default: true for cost optimization) */
|
|
37
|
+
compress?: boolean;
|
|
38
|
+
/** Gzip compression level 1-9 (default: 6, balanced speed/size) */
|
|
39
|
+
compressionLevel?: number;
|
|
40
|
+
/** Optional callback to track upload progress */
|
|
41
|
+
progressCallback?: (bytesUploaded: number, totalBytes: number) => void;
|
|
42
|
+
}
|
|
43
|
+
export interface Dataset {
|
|
44
|
+
_id?: string;
|
|
45
|
+
dataset_id?: string;
|
|
46
|
+
name: string;
|
|
47
|
+
description: string;
|
|
48
|
+
producer_id: string;
|
|
49
|
+
category: string;
|
|
50
|
+
data_freshness: string;
|
|
51
|
+
s3_key: string;
|
|
52
|
+
size_bytes: number;
|
|
53
|
+
metadata?: Record<string, any>;
|
|
54
|
+
}
|
|
55
|
+
export declare class HelixProducer {
|
|
56
|
+
private customerId;
|
|
57
|
+
private apiEndpoint;
|
|
58
|
+
private region;
|
|
59
|
+
private bucketName;
|
|
60
|
+
private kmsKeyId;
|
|
61
|
+
private kmsClient;
|
|
62
|
+
private s3Client;
|
|
63
|
+
private stsClient;
|
|
64
|
+
private awsAccessKeyId;
|
|
65
|
+
private awsSecretAccessKey;
|
|
66
|
+
/**
|
|
67
|
+
* Creates a new Helix Producer instance.
|
|
68
|
+
* Initializes AWS clients, validates credentials, and retrieves producer-specific resources from SSM.
|
|
69
|
+
*/
|
|
70
|
+
constructor(config: HelixProducerConfig);
|
|
71
|
+
/**
|
|
72
|
+
* Initializes the producer by validating credentials and retrieving S3 bucket and KMS key from SSM.
|
|
73
|
+
* Called automatically during construction.
|
|
74
|
+
*/
|
|
75
|
+
private initialize;
|
|
76
|
+
/**
|
|
77
|
+
* Compresses data using gzip compression.
|
|
78
|
+
* Compression works best on unencrypted data due to patterns and redundancy.
|
|
79
|
+
*/
|
|
80
|
+
private compressData;
|
|
81
|
+
/**
|
|
82
|
+
* Encrypts data using envelope encryption with KMS and AES-256-GCM.
|
|
83
|
+
* Process: Generate data key, encrypt data with data key, encrypt data key with KMS.
|
|
84
|
+
* Format: [4 bytes: key length][encrypted key][16 bytes: IV][16 bytes: tag][encrypted data]
|
|
85
|
+
*/
|
|
86
|
+
private encryptData;
|
|
87
|
+
/**
|
|
88
|
+
* Uploads a dataset with encryption and compression.
|
|
89
|
+
*
|
|
90
|
+
* Security and Performance Defaults (v2.0+):
|
|
91
|
+
* - Encryption is ENABLED by default (KMS envelope encryption)
|
|
92
|
+
* - Compression is ENABLED by default (gzip compression level 6)
|
|
93
|
+
* - This provides security by default and reduces S3 storage costs
|
|
94
|
+
*
|
|
95
|
+
* Process:
|
|
96
|
+
* 1. Compress data first (if enabled) - works best on unencrypted data
|
|
97
|
+
* 2. Encrypt compressed data (if enabled) - KMS envelope encryption
|
|
98
|
+
* 3. Upload to S3 with generated S3 key
|
|
99
|
+
* 4. Register dataset in catalog via API
|
|
100
|
+
*
|
|
101
|
+
* Example with secure defaults:
|
|
102
|
+
* ```typescript
|
|
103
|
+
* const producer = new HelixProducer({...});
|
|
104
|
+
* const dataset = await producer.uploadDataset('/path/to/data.ndjson', {
|
|
105
|
+
* datasetName: 'my-dataset',
|
|
106
|
+
* description: 'My dataset'
|
|
107
|
+
* // encrypt and compress default to true
|
|
108
|
+
* });
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* To disable (not recommended for sensitive data):
|
|
112
|
+
* ```typescript
|
|
113
|
+
* await producer.uploadDataset(filePath, {
|
|
114
|
+
* datasetName: 'my-dataset',
|
|
115
|
+
* encrypt: false, // Disable encryption
|
|
116
|
+
* compress: false // Disable compression
|
|
117
|
+
* });
|
|
118
|
+
* ```
|
|
119
|
+
*
|
|
120
|
+
* @param filePath - Local path to the dataset file
|
|
121
|
+
* @param options - Upload options with secure defaults
|
|
122
|
+
* @returns Dataset metadata including ID and S3 key
|
|
123
|
+
* @throws Error if file not found, encryption fails, or upload fails
|
|
124
|
+
*/
|
|
125
|
+
uploadDataset(filePath: string, options: UploadOptions): Promise<Dataset>;
|
|
126
|
+
/**
|
|
127
|
+
* Lists all datasets uploaded by this producer.
|
|
128
|
+
* Returns metadata for all datasets owned by the current producer account.
|
|
129
|
+
*/
|
|
130
|
+
listMyDatasets(): Promise<Dataset[]>;
|
|
131
|
+
/**
|
|
132
|
+
* Signs an HTTP request using AWS Signature Version 4.
|
|
133
|
+
* Used for authenticating API requests to Helix Connect Platform.
|
|
134
|
+
*/
|
|
135
|
+
private signRequest;
|
|
136
|
+
/**
|
|
137
|
+
* Lists incoming subscription requests for this producer.
|
|
138
|
+
* Returns requests that match the specified status filter.
|
|
139
|
+
*/
|
|
140
|
+
listSubscriptionRequests(status?: 'pending' | 'approved' | 'rejected'): Promise<any[]>;
|
|
141
|
+
/**
|
|
142
|
+
* Approves a subscription request from a consumer.
|
|
143
|
+
* Creates the necessary resources (SQS queue, SNS subscription) for the consumer.
|
|
144
|
+
*/
|
|
145
|
+
approveSubscriptionRequest(requestId: string, notes?: string): Promise<any>;
|
|
146
|
+
/**
|
|
147
|
+
* Rejects a subscription request from a consumer.
|
|
148
|
+
*/
|
|
149
|
+
rejectSubscriptionRequest(requestId: string, reason?: string): Promise<any>;
|
|
150
|
+
/**
|
|
151
|
+
* Makes an authenticated API request with form-encoded data.
|
|
152
|
+
*/
|
|
153
|
+
private makeFormApiRequest;
|
|
154
|
+
/**
|
|
155
|
+
* Makes an authenticated API request to Helix Connect Platform.
|
|
156
|
+
* Handles request signing, error responses, and retries.
|
|
157
|
+
*/
|
|
158
|
+
private makeApiRequest;
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=producer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"producer.d.ts","sourceRoot":"","sources":["../src/producer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,aAAa;IAC5B,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAC;IAEpB,iCAAiC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,mDAAmD;IACnD,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAE/B,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,mEAAmE;IACnE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,iDAAiD;IACjD,gBAAgB,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;CACxE;AAED,MAAM,WAAW,OAAO;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,kBAAkB,CAAS;IAEnC;;;OAGG;gBACS,MAAM,EAAE,mBAAmB;IA4BvC;;;OAGG;YACW,UAAU;IAoDxB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAUpB;;;;OAIG;YACW,WAAW;IA4DzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqCG;IACG,aAAa,CACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,OAAO,CAAC;IAkHnB;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAc1C;;;OAGG;YACW,WAAW;IAyCzB;;;OAGG;IACG,wBAAwB,CAAC,MAAM,GAAE,SAAS,GAAG,UAAU,GAAG,UAAsB,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAQvG;;;OAGG;IACG,0BAA0B,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAajF;;OAEG;IACG,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAajF;;OAEG;YACW,kBAAkB;IAsChC;;;OAGG;YACW,cAAc;CAqC7B"}
|
package/dist/producer.js
ADDED
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Helix Connect Platform Producer SDK
|
|
4
|
+
* For data producers who want to upload and manage datasets
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
40
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
41
|
+
};
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.HelixProducer = void 0;
|
|
44
|
+
const client_kms_1 = require("@aws-sdk/client-kms");
|
|
45
|
+
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
46
|
+
const client_ssm_1 = require("@aws-sdk/client-ssm");
|
|
47
|
+
const client_sts_1 = require("@aws-sdk/client-sts");
|
|
48
|
+
const signature_v4_1 = require("@smithy/signature-v4");
|
|
49
|
+
const protocol_http_1 = require("@smithy/protocol-http");
|
|
50
|
+
const sha256_js_1 = require("@aws-crypto/sha256-js");
|
|
51
|
+
const axios_1 = __importDefault(require("axios"));
|
|
52
|
+
const pako = __importStar(require("pako"));
|
|
53
|
+
const fs = __importStar(require("fs"));
|
|
54
|
+
const crypto = __importStar(require("crypto"));
|
|
55
|
+
class HelixProducer {
|
|
56
|
+
/**
|
|
57
|
+
* Creates a new Helix Producer instance.
|
|
58
|
+
* Initializes AWS clients, validates credentials, and retrieves producer-specific resources from SSM.
|
|
59
|
+
*/
|
|
60
|
+
constructor(config) {
|
|
61
|
+
this.customerId = config.customerId;
|
|
62
|
+
this.apiEndpoint = (config.apiEndpoint || 'https://api.helix.tools').replace(/\/$/, '');
|
|
63
|
+
this.region = config.region || 'us-east-1';
|
|
64
|
+
this.awsAccessKeyId = config.awsAccessKeyId;
|
|
65
|
+
this.awsSecretAccessKey = config.awsSecretAccessKey;
|
|
66
|
+
// Initialize AWS clients
|
|
67
|
+
const awsConfig = {
|
|
68
|
+
region: this.region,
|
|
69
|
+
credentials: {
|
|
70
|
+
accessKeyId: this.awsAccessKeyId,
|
|
71
|
+
secretAccessKey: this.awsSecretAccessKey,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
this.kmsClient = new client_kms_1.KMSClient(awsConfig);
|
|
75
|
+
this.s3Client = new client_s3_1.S3Client(awsConfig);
|
|
76
|
+
this.stsClient = new client_sts_1.STSClient(awsConfig);
|
|
77
|
+
// Will be populated after validation
|
|
78
|
+
this.bucketName = '';
|
|
79
|
+
this.kmsKeyId = '';
|
|
80
|
+
// Validate credentials and get producer resources
|
|
81
|
+
this.initialize();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Initializes the producer by validating credentials and retrieving S3 bucket and KMS key from SSM.
|
|
85
|
+
* Called automatically during construction.
|
|
86
|
+
*/
|
|
87
|
+
async initialize() {
|
|
88
|
+
// Validate credentials
|
|
89
|
+
try {
|
|
90
|
+
const command = new client_sts_1.GetCallerIdentityCommand({});
|
|
91
|
+
await this.stsClient.send(command);
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
throw new Error(`Invalid AWS credentials. Please check your access key and secret key. Error: ${error}`);
|
|
95
|
+
}
|
|
96
|
+
// Get producer-specific resources from SSM
|
|
97
|
+
const ssmClient = new client_ssm_1.SSMClient({
|
|
98
|
+
region: this.region,
|
|
99
|
+
credentials: {
|
|
100
|
+
accessKeyId: this.awsAccessKeyId,
|
|
101
|
+
secretAccessKey: this.awsSecretAccessKey,
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
try {
|
|
105
|
+
// Get S3 bucket name
|
|
106
|
+
const bucketParam = `/helix/customers/${this.customerId}/s3_bucket`;
|
|
107
|
+
const bucketResponse = await ssmClient.send(new client_ssm_1.GetParameterCommand({ Name: bucketParam }));
|
|
108
|
+
if (!bucketResponse.Parameter?.Value) {
|
|
109
|
+
throw new Error(`S3 bucket not found for producer ${this.customerId}`);
|
|
110
|
+
}
|
|
111
|
+
this.bucketName = bucketResponse.Parameter.Value;
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
throw new Error(`S3 bucket not found for producer ${this.customerId}: ${error}`);
|
|
115
|
+
}
|
|
116
|
+
// Get KMS key ID (optional for producers)
|
|
117
|
+
try {
|
|
118
|
+
const kmsParam = `/helix/customers/${this.customerId}/kms_key_id`;
|
|
119
|
+
const kmsResponse = await ssmClient.send(new client_ssm_1.GetParameterCommand({ Name: kmsParam }));
|
|
120
|
+
if (kmsResponse.Parameter?.Value) {
|
|
121
|
+
this.kmsKeyId = kmsResponse.Parameter.Value;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
console.log(`Warning: KMS key not found, encryption will be disabled: ${error}`);
|
|
126
|
+
this.kmsKeyId = '';
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Compresses data using gzip compression.
|
|
131
|
+
* Compression works best on unencrypted data due to patterns and redundancy.
|
|
132
|
+
*/
|
|
133
|
+
compressData(data, level) {
|
|
134
|
+
try {
|
|
135
|
+
// pako expects specific compression levels: 0-9, -1
|
|
136
|
+
const validLevel = Math.max(0, Math.min(9, Math.floor(level)));
|
|
137
|
+
return Buffer.from(pako.gzip(data, { level: validLevel }));
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
throw new Error(`Compression failed: ${error}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Encrypts data using envelope encryption with KMS and AES-256-GCM.
|
|
145
|
+
* Process: Generate data key, encrypt data with data key, encrypt data key with KMS.
|
|
146
|
+
* Format: [4 bytes: key length][encrypted key][16 bytes: IV][16 bytes: tag][encrypted data]
|
|
147
|
+
*/
|
|
148
|
+
async encryptData(data) {
|
|
149
|
+
if (!this.kmsKeyId) {
|
|
150
|
+
throw new Error('KMS key not configured, cannot encrypt data');
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
// Generate random data key and IV
|
|
154
|
+
const dataKey = crypto.randomBytes(32); // 256-bit key for AES-256
|
|
155
|
+
const iv = crypto.randomBytes(16); // 128-bit IV for GCM mode
|
|
156
|
+
// Encrypt data with data key using AES-256-GCM
|
|
157
|
+
const cipher = crypto.createCipheriv('aes-256-gcm', dataKey, iv);
|
|
158
|
+
const encryptedData = Buffer.concat([
|
|
159
|
+
cipher.update(data),
|
|
160
|
+
cipher.final(),
|
|
161
|
+
]);
|
|
162
|
+
const authTag = cipher.getAuthTag();
|
|
163
|
+
// Encrypt the data key with KMS (only 32 bytes, well under 4KB limit)
|
|
164
|
+
const encryptCommand = new client_kms_1.EncryptCommand({
|
|
165
|
+
KeyId: this.kmsKeyId,
|
|
166
|
+
Plaintext: dataKey,
|
|
167
|
+
});
|
|
168
|
+
const encryptResult = await this.kmsClient.send(encryptCommand);
|
|
169
|
+
if (!encryptResult.CiphertextBlob) {
|
|
170
|
+
throw new Error('KMS encryption returned no ciphertext');
|
|
171
|
+
}
|
|
172
|
+
const encryptedKey = Buffer.from(encryptResult.CiphertextBlob);
|
|
173
|
+
// Package: [4 bytes: key length][encrypted key][16 bytes: IV][16 bytes: tag][encrypted data]
|
|
174
|
+
const result = Buffer.allocUnsafe(4 + encryptedKey.length + 16 + 16 + encryptedData.length);
|
|
175
|
+
let offset = 0;
|
|
176
|
+
// Write encrypted key length (4 bytes, big-endian)
|
|
177
|
+
result.writeUInt32BE(encryptedKey.length, offset);
|
|
178
|
+
offset += 4;
|
|
179
|
+
// Write encrypted key
|
|
180
|
+
encryptedKey.copy(result, offset);
|
|
181
|
+
offset += encryptedKey.length;
|
|
182
|
+
// Write IV (16 bytes)
|
|
183
|
+
iv.copy(result, offset);
|
|
184
|
+
offset += 16;
|
|
185
|
+
// Write auth tag (16 bytes)
|
|
186
|
+
authTag.copy(result, offset);
|
|
187
|
+
offset += 16;
|
|
188
|
+
// Write encrypted data
|
|
189
|
+
encryptedData.copy(result, offset);
|
|
190
|
+
return result;
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
throw new Error(`Encryption failed: ${error}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Uploads a dataset with encryption and compression.
|
|
198
|
+
*
|
|
199
|
+
* Security and Performance Defaults (v2.0+):
|
|
200
|
+
* - Encryption is ENABLED by default (KMS envelope encryption)
|
|
201
|
+
* - Compression is ENABLED by default (gzip compression level 6)
|
|
202
|
+
* - This provides security by default and reduces S3 storage costs
|
|
203
|
+
*
|
|
204
|
+
* Process:
|
|
205
|
+
* 1. Compress data first (if enabled) - works best on unencrypted data
|
|
206
|
+
* 2. Encrypt compressed data (if enabled) - KMS envelope encryption
|
|
207
|
+
* 3. Upload to S3 with generated S3 key
|
|
208
|
+
* 4. Register dataset in catalog via API
|
|
209
|
+
*
|
|
210
|
+
* Example with secure defaults:
|
|
211
|
+
* ```typescript
|
|
212
|
+
* const producer = new HelixProducer({...});
|
|
213
|
+
* const dataset = await producer.uploadDataset('/path/to/data.ndjson', {
|
|
214
|
+
* datasetName: 'my-dataset',
|
|
215
|
+
* description: 'My dataset'
|
|
216
|
+
* // encrypt and compress default to true
|
|
217
|
+
* });
|
|
218
|
+
* ```
|
|
219
|
+
*
|
|
220
|
+
* To disable (not recommended for sensitive data):
|
|
221
|
+
* ```typescript
|
|
222
|
+
* await producer.uploadDataset(filePath, {
|
|
223
|
+
* datasetName: 'my-dataset',
|
|
224
|
+
* encrypt: false, // Disable encryption
|
|
225
|
+
* compress: false // Disable compression
|
|
226
|
+
* });
|
|
227
|
+
* ```
|
|
228
|
+
*
|
|
229
|
+
* @param filePath - Local path to the dataset file
|
|
230
|
+
* @param options - Upload options with secure defaults
|
|
231
|
+
* @returns Dataset metadata including ID and S3 key
|
|
232
|
+
* @throws Error if file not found, encryption fails, or upload fails
|
|
233
|
+
*/
|
|
234
|
+
async uploadDataset(filePath, options) {
|
|
235
|
+
// Set defaults (encryption and compression enabled by default)
|
|
236
|
+
const category = options.category || 'general';
|
|
237
|
+
const dataFreshness = options.dataFreshness || 'daily';
|
|
238
|
+
const compress = options.compress !== false; // Default: true
|
|
239
|
+
let encrypt = options.encrypt !== false; // Default: true
|
|
240
|
+
const compressionLevel = options.compressionLevel || 6;
|
|
241
|
+
// Check if file exists
|
|
242
|
+
if (!fs.existsSync(filePath)) {
|
|
243
|
+
throw new Error(`File not found: ${filePath}`);
|
|
244
|
+
}
|
|
245
|
+
// Read original file
|
|
246
|
+
let data = fs.readFileSync(filePath);
|
|
247
|
+
const originalSize = data.length;
|
|
248
|
+
// Track sizes for metadata
|
|
249
|
+
const sizes = {
|
|
250
|
+
original_size_bytes: originalSize,
|
|
251
|
+
compressed_size_bytes: originalSize,
|
|
252
|
+
encrypted_size_bytes: originalSize,
|
|
253
|
+
encryption_enabled: encrypt,
|
|
254
|
+
compression_enabled: compress,
|
|
255
|
+
};
|
|
256
|
+
// Step 1: Compress FIRST (if enabled)
|
|
257
|
+
// Compression works best on unencrypted data due to patterns/redundancy
|
|
258
|
+
if (compress) {
|
|
259
|
+
console.log(`📦 Compressing ${data.length} bytes with gzip (level ${compressionLevel})...`);
|
|
260
|
+
const compressed = this.compressData(data, compressionLevel);
|
|
261
|
+
data = compressed;
|
|
262
|
+
sizes.compressed_size_bytes = data.length;
|
|
263
|
+
const compressionRatio = (1 - data.length / originalSize) * 100;
|
|
264
|
+
console.log(`Compressed: ${data.length} bytes (${compressionRatio.toFixed(1)}% reduction)`);
|
|
265
|
+
}
|
|
266
|
+
// Step 2: Encrypt SECOND (if enabled)
|
|
267
|
+
// Encrypt the compressed data for security
|
|
268
|
+
if (encrypt) {
|
|
269
|
+
if (!this.kmsKeyId) {
|
|
270
|
+
console.log('Warning: Encryption requested but KMS key not found. Skipping encryption.');
|
|
271
|
+
encrypt = false;
|
|
272
|
+
sizes.encryption_enabled = false;
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
console.log(`🔒 Encrypting ${data.length} bytes with KMS key...`);
|
|
276
|
+
const encrypted = await this.encryptData(data);
|
|
277
|
+
data = encrypted;
|
|
278
|
+
sizes.encrypted_size_bytes = data.length;
|
|
279
|
+
console.log(`Encrypted: ${data.length} bytes`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
// Generate S3 key with consistent filename (no date, no randomness)
|
|
283
|
+
// This enables in-place updates - same dataset name = same S3 key = file overwrite
|
|
284
|
+
let fileName = 'data.ndjson';
|
|
285
|
+
if (compress) {
|
|
286
|
+
fileName += '.gz';
|
|
287
|
+
}
|
|
288
|
+
const s3Key = `datasets/${options.datasetName}/${fileName}`;
|
|
289
|
+
// Build S3 object tags for cost tracking
|
|
290
|
+
// Format: CustomerID=value&Component=storage&Purpose=dataset-storage&DatasetName=value
|
|
291
|
+
const tags = [
|
|
292
|
+
`CustomerID=${encodeURIComponent(this.customerId)}`,
|
|
293
|
+
`Component=${encodeURIComponent('storage')}`,
|
|
294
|
+
`Purpose=${encodeURIComponent('dataset-storage')}`,
|
|
295
|
+
`DatasetName=${encodeURIComponent(options.datasetName)}`,
|
|
296
|
+
].join('&');
|
|
297
|
+
// Upload to S3
|
|
298
|
+
console.log(`📤 Uploading ${data.length} bytes to S3...`);
|
|
299
|
+
try {
|
|
300
|
+
const putCommand = new client_s3_1.PutObjectCommand({
|
|
301
|
+
Bucket: this.bucketName,
|
|
302
|
+
Key: s3Key,
|
|
303
|
+
Body: data, // Buffer is compatible with Body type
|
|
304
|
+
Tagging: tags,
|
|
305
|
+
});
|
|
306
|
+
await this.s3Client.send(putCommand);
|
|
307
|
+
console.log(`✅ Uploaded to s3://${this.bucketName}/${s3Key} (tagged: CustomerID=${this.customerId})`);
|
|
308
|
+
}
|
|
309
|
+
catch (error) {
|
|
310
|
+
throw new Error(`Failed to upload file: ${error}`);
|
|
311
|
+
}
|
|
312
|
+
// Register dataset in catalog via API
|
|
313
|
+
const payload = {
|
|
314
|
+
name: options.datasetName,
|
|
315
|
+
description: options.description || '',
|
|
316
|
+
producer_id: this.customerId,
|
|
317
|
+
category,
|
|
318
|
+
data_freshness: dataFreshness,
|
|
319
|
+
s3_key: s3Key,
|
|
320
|
+
size_bytes: sizes.compressed_size_bytes,
|
|
321
|
+
metadata: { ...(options.metadata || {}), ...sizes },
|
|
322
|
+
};
|
|
323
|
+
try {
|
|
324
|
+
const dataset = await this.makeApiRequest('POST', '/v1/datasets', payload);
|
|
325
|
+
return dataset;
|
|
326
|
+
}
|
|
327
|
+
catch (error) {
|
|
328
|
+
// Upload succeeded but registration failed - log warning
|
|
329
|
+
console.log(`⚠️ Warning: File uploaded but catalog registration failed: ${error}`);
|
|
330
|
+
return {
|
|
331
|
+
...payload,
|
|
332
|
+
metadata: {
|
|
333
|
+
...payload.metadata,
|
|
334
|
+
status: 'uploaded_unregistered',
|
|
335
|
+
error: String(error),
|
|
336
|
+
},
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Lists all datasets uploaded by this producer.
|
|
342
|
+
* Returns metadata for all datasets owned by the current producer account.
|
|
343
|
+
*/
|
|
344
|
+
async listMyDatasets() {
|
|
345
|
+
const response = await this.makeApiRequest('GET', `/v1/datasets?producer_id=${encodeURIComponent(this.customerId)}`);
|
|
346
|
+
return response.datasets;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Signs an HTTP request using AWS Signature Version 4.
|
|
350
|
+
* Used for authenticating API requests to Helix Connect Platform.
|
|
351
|
+
*/
|
|
352
|
+
async signRequest(method, path, body, contentType = 'application/json') {
|
|
353
|
+
const url = new URL(this.apiEndpoint + path);
|
|
354
|
+
// Parse query parameters separately for proper SigV4 signing
|
|
355
|
+
const queryParams = {};
|
|
356
|
+
url.searchParams.forEach((value, key) => {
|
|
357
|
+
queryParams[key] = value;
|
|
358
|
+
});
|
|
359
|
+
const request = new protocol_http_1.HttpRequest({
|
|
360
|
+
method,
|
|
361
|
+
protocol: url.protocol,
|
|
362
|
+
hostname: url.hostname,
|
|
363
|
+
path: url.pathname, // Path without query string
|
|
364
|
+
query: Object.keys(queryParams).length > 0 ? queryParams : undefined, // Query params separately
|
|
365
|
+
headers: {
|
|
366
|
+
'Content-Type': contentType,
|
|
367
|
+
host: url.hostname,
|
|
368
|
+
},
|
|
369
|
+
body,
|
|
370
|
+
});
|
|
371
|
+
const signer = new signature_v4_1.SignatureV4({
|
|
372
|
+
credentials: {
|
|
373
|
+
accessKeyId: this.awsAccessKeyId,
|
|
374
|
+
secretAccessKey: this.awsSecretAccessKey,
|
|
375
|
+
},
|
|
376
|
+
region: this.region,
|
|
377
|
+
service: 'execute-api',
|
|
378
|
+
sha256: sha256_js_1.Sha256,
|
|
379
|
+
});
|
|
380
|
+
const signedRequest = await signer.sign(request);
|
|
381
|
+
return signedRequest.headers;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Lists incoming subscription requests for this producer.
|
|
385
|
+
* Returns requests that match the specified status filter.
|
|
386
|
+
*/
|
|
387
|
+
async listSubscriptionRequests(status = 'pending') {
|
|
388
|
+
const response = await this.makeApiRequest('GET', `/v1/producers/subscription-requests?status=${status}`);
|
|
389
|
+
return response.requests || response;
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Approves a subscription request from a consumer.
|
|
393
|
+
* Creates the necessary resources (SQS queue, SNS subscription) for the consumer.
|
|
394
|
+
*/
|
|
395
|
+
async approveSubscriptionRequest(requestId, notes) {
|
|
396
|
+
const formData = { action: 'approve' };
|
|
397
|
+
if (notes) {
|
|
398
|
+
formData.notes = notes;
|
|
399
|
+
}
|
|
400
|
+
const response = await this.makeFormApiRequest('POST', `/v1/subscription-requests/${requestId}`, formData);
|
|
401
|
+
return response;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Rejects a subscription request from a consumer.
|
|
405
|
+
*/
|
|
406
|
+
async rejectSubscriptionRequest(requestId, reason) {
|
|
407
|
+
const formData = { action: 'reject' };
|
|
408
|
+
if (reason) {
|
|
409
|
+
formData.reason = reason;
|
|
410
|
+
}
|
|
411
|
+
const response = await this.makeFormApiRequest('POST', `/v1/subscription-requests/${requestId}`, formData);
|
|
412
|
+
return response;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Makes an authenticated API request with form-encoded data.
|
|
416
|
+
*/
|
|
417
|
+
async makeFormApiRequest(method, path, formData) {
|
|
418
|
+
const body = formData ? new URLSearchParams(formData).toString() : undefined;
|
|
419
|
+
const headers = await this.signRequest(method, path, body, 'application/x-www-form-urlencoded');
|
|
420
|
+
const config = {
|
|
421
|
+
method,
|
|
422
|
+
url: this.apiEndpoint + path,
|
|
423
|
+
headers,
|
|
424
|
+
data: body,
|
|
425
|
+
timeout: 30000,
|
|
426
|
+
};
|
|
427
|
+
try {
|
|
428
|
+
const response = await (0, axios_1.default)(config);
|
|
429
|
+
return response.data;
|
|
430
|
+
}
|
|
431
|
+
catch (error) {
|
|
432
|
+
if (error.response) {
|
|
433
|
+
const status = error.response.status;
|
|
434
|
+
const message = error.response.data?.error || error.response.statusText;
|
|
435
|
+
if (status === 401) {
|
|
436
|
+
throw new Error(`Authentication failed: ${message}`);
|
|
437
|
+
}
|
|
438
|
+
else if (status === 403) {
|
|
439
|
+
throw new Error(`Permission denied: ${message}`);
|
|
440
|
+
}
|
|
441
|
+
else if (status === 404) {
|
|
442
|
+
throw new Error(`Resource not found: ${message}`);
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
throw new Error(`API request failed: ${status} - ${message}`);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
throw error;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Makes an authenticated API request to Helix Connect Platform.
|
|
453
|
+
* Handles request signing, error responses, and retries.
|
|
454
|
+
*/
|
|
455
|
+
async makeApiRequest(method, path, data) {
|
|
456
|
+
const body = data ? JSON.stringify(data) : undefined;
|
|
457
|
+
const headers = await this.signRequest(method, path, body);
|
|
458
|
+
const config = {
|
|
459
|
+
method,
|
|
460
|
+
url: this.apiEndpoint + path,
|
|
461
|
+
headers,
|
|
462
|
+
data,
|
|
463
|
+
timeout: 30000, // 30 second timeout
|
|
464
|
+
};
|
|
465
|
+
try {
|
|
466
|
+
const response = await (0, axios_1.default)(config);
|
|
467
|
+
return response.data;
|
|
468
|
+
}
|
|
469
|
+
catch (error) {
|
|
470
|
+
if (error.response) {
|
|
471
|
+
const status = error.response.status;
|
|
472
|
+
const message = error.response.data?.error || error.response.statusText;
|
|
473
|
+
if (status === 401) {
|
|
474
|
+
throw new Error(`Authentication failed: ${message}`);
|
|
475
|
+
}
|
|
476
|
+
else if (status === 403) {
|
|
477
|
+
throw new Error(`Permission denied: ${message}`);
|
|
478
|
+
}
|
|
479
|
+
else if (status === 404) {
|
|
480
|
+
throw new Error(`Resource not found: ${message}`);
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
throw new Error(`API request failed: ${status} - ${message}`);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
throw error;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
exports.HelixProducer = HelixProducer;
|
|
491
|
+
//# sourceMappingURL=producer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"producer.js","sourceRoot":"","sources":["../src/producer.ts"],"names":[],"mappings":"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"}
|