@forzalabs/remora 0.0.12 → 0.0.13

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.
@@ -1,4 +1,5 @@
1
1
  {
2
+ "$schema": "https://raw.githubusercontent.com/ForzaLabs/remora-public/refs/heads/main/json_schemas/consumer-schema.json",
2
3
  "name": "<consumer name>",
3
4
  "description": "<consumer description>",
4
5
  "producers": [
@@ -1,4 +1,5 @@
1
1
  {
2
+ "$schema": "https://raw.githubusercontent.com/ForzaLabs/remora-public/refs/heads/main/json_schemas/producer-schema.json",
2
3
  "name": "<producer name>",
3
4
  "description": "<producer description>",
4
5
  "source": "<source name>",
@@ -1,4 +1,5 @@
1
1
  {
2
+ "$schema": "https://raw.githubusercontent.com/ForzaLabs/remora-public/refs/heads/main/json_schemas/project-schema.json",
2
3
  "name": "PROJECT_NAME_EXAMPLE",
3
4
  "version": "1.0.0",
4
5
  "description": "DESCRIPTION_OF_THIS_PROJECT",
@@ -1,7 +1,7 @@
1
1
  {
2
- "$schema": "<http://json-schema.org/draft-07/schema#>",
3
- "title": "<schema title>",
4
- "type": "<object>",
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "<example schema>",
4
+ "type": "object",
5
5
  "version": 1,
6
6
  "description": "<schema description>",
7
7
  "properties": {
@@ -1,4 +1,5 @@
1
1
  {
2
+ "$schema": "https://raw.githubusercontent.com/ForzaLabs/remora-public/refs/heads/main/json_schemas/source-schema.json",
2
3
  "name": "<source name>",
3
4
  "description": "<source description>",
4
5
  "_version": 1,
@@ -16,6 +16,7 @@ const client_redshift_data_1 = require("@aws-sdk/client-redshift-data");
16
16
  const Affirm_1 = __importDefault(require("../core/Affirm"));
17
17
  const Algo_1 = __importDefault(require("../core/Algo"));
18
18
  const Environment_1 = __importDefault(require("../engines/Environment"));
19
+ const SecretManager_1 = __importDefault(require("../engines/SecretManager"));
19
20
  class RedshiftDriver {
20
21
  constructor() {
21
22
  this.init = (source) => __awaiter(this, void 0, void 0, function* () {
@@ -23,12 +24,13 @@ class RedshiftDriver {
23
24
  this._SQL_MAX_QUERY_ROWS = parseInt(Environment_1.default.get('SQL_MAX_QUERY_ROWS'));
24
25
  this._dbName = source.authentication['database'];
25
26
  this._workgroup = source.authentication['workgroup'];
27
+ const sessionToken = SecretManager_1.default.replaceSecret(source.authentication['sessionToken']);
26
28
  const config = {
27
29
  region: source.authentication['region'],
28
30
  credentials: {
29
- accessKeyId: source.authentication['accessKey'],
30
- secretAccessKey: source.authentication['secretKey']
31
- // sessionToken: 'IQoJb3JpZ2luX2VjEDQaCXVzLWVhc3QtMSJIMEYCIQDXHjVYaGyCWCMgYWmnYt652z02H+w0jia8l/ckgu+gSAIhAOaKqkWbitaywpIy4l3lXQfQqW/fYhd187jRsL0kkm+wKokDCCwQABoMNzMwMzM1MTgwOTE5Igz36Yz4UuTQ6KuP5lcq5gKi1zczRVbAI6fnKQGNqg2k18/wJFpQgINNW+Ae9BoFofarAlOkXO5qeloP/5dGMufPVu/hy4tqaDi0Jpz8Zpa1JJjj6Q4l7XZi0+SpCkWwoVRsM/8ojMzowTWnUzan17I0jnG4TQKVEABQjQEACbJMbPwHNm1cN+dEY14cTyA36yJ0ma+8GDLECYnBM4klHKxzYJbD2tdwSgW4KAZ2ttk9+AnrKJUVH4hDI4cPBRv8uIUKGGfzD8cRpMGCByYeLVPc0o5IFCZGqkHncRlAU7dH0xZyGyCeDo3Z3819Ll8vJ41RN4RQOwcWrmL1Ne73KRgH32Ya9xH5j052WxERJPouCk+Lj307XmL0YwpkiQtV7cK5bQQRHtihviGkiK4maZLXXy7aUPQQG57xc0Q3HJXdI6LiXhvKvPKQm2iwAQS+FUZeekf1msT6MkVWd1ibYyhMzFeHBBPvVDlc4NFtLH6rGKAGgkuaMLGunrwGOqUB+nVvTAgcT7amelZRma0TRJsfFezBCAXXWNurD/6qAAKpKgmP+ouE+gH+SmG67IbQqIzK/5dc53sMV7dXDdG4/XGvmWfTph1iHZN/c1bd/rYPfVzy3K3ybTe2Djj0IaTbNndxVPfWIU6cC6cJ6ahEMvzokNnKNUqdDnu/Z1S2xiOfV4P/9vTg7O1XuLUylsCzveeYWRoZJPY4XCUnOgNlqQ/ZwKTC'
31
+ accessKeyId: SecretManager_1.default.replaceSecret(source.authentication['accessKey']),
32
+ secretAccessKey: SecretManager_1.default.replaceSecret(source.authentication['secretKey']),
33
+ sessionToken: sessionToken ? sessionToken : undefined
32
34
  }
33
35
  };
34
36
  try {
@@ -14,15 +14,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  const client_s3_1 = require("@aws-sdk/client-s3");
16
16
  const Affirm_1 = __importDefault(require("../core/Affirm"));
17
+ const SecretManager_1 = __importDefault(require("../engines/SecretManager"));
17
18
  class S3Driver {
18
19
  constructor() {
19
20
  this.init = (source) => __awaiter(this, void 0, void 0, function* () {
20
21
  this._bucketName = source.authentication['bucketName'];
22
+ const sessionToken = SecretManager_1.default.replaceSecret(source.authentication['sessionToken']);
21
23
  const config = {
22
24
  region: source.authentication['region'],
23
25
  credentials: {
24
- accessKeyId: source.authentication['accessKey'],
25
- secretAccessKey: source.authentication['secretKey']
26
+ accessKeyId: SecretManager_1.default.replaceSecret(source.authentication['accessKey']),
27
+ secretAccessKey: SecretManager_1.default.replaceSecret(source.authentication['secretKey']),
28
+ sessionToken: sessionToken ? sessionToken : undefined
26
29
  }
27
30
  };
28
31
  this._client = new client_s3_1.S3Client(config);
@@ -22,15 +22,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
22
22
  const client_s3_1 = require("@aws-sdk/client-s3");
23
23
  const readline_1 = __importDefault(require("readline"));
24
24
  const Affirm_1 = __importDefault(require("../core/Affirm"));
25
+ const SecretManager_1 = __importDefault(require("../engines/SecretManager"));
25
26
  class S3SourceDriver {
26
27
  constructor() {
27
28
  this.init = (source) => __awaiter(this, void 0, void 0, function* () {
28
29
  this._bucketName = source.authentication['bucketName'];
30
+ const sessionToken = SecretManager_1.default.replaceSecret(source.authentication['sessionToken']);
29
31
  const config = {
30
32
  region: source.authentication['region'],
31
33
  credentials: {
32
- accessKeyId: source.authentication['accessKey'],
33
- secretAccessKey: source.authentication['secretKey']
34
+ accessKeyId: SecretManager_1.default.replaceSecret(source.authentication['accessKey']),
35
+ secretAccessKey: SecretManager_1.default.replaceSecret(source.authentication['secretKey']),
36
+ sessionToken: sessionToken ? sessionToken : undefined
34
37
  }
35
38
  };
36
39
  this._client = new client_s3_1.S3Client(config);
@@ -73,9 +73,7 @@ class EnvironmentClass {
73
73
  });
74
74
  // Initialize environment
75
75
  this.init({
76
- settings: new Map(Object.entries({
77
- SQL_MAX_QUERY_ROWS: projectConfig.settings.SQL_MAX_QUERY_ROWS.toString()
78
- })),
76
+ settings: new Map(Object.entries(Object.assign({}, projectConfig.settings)).map(([key, value]) => [key, String(value)])),
79
77
  sources,
80
78
  producers,
81
79
  consumers,
@@ -51,8 +51,8 @@ class ProducerEngineClass {
51
51
  for (const planStep of plan) {
52
52
  switch (planStep.type) {
53
53
  case 'create-view': {
54
- const internalSchema = Environment_1.default.get('schema');
55
- (0, Affirm_1.default)(internalSchema, `Invalid schema set on the authentication for source "${source.name}"`);
54
+ const internalSchema = Environment_1.default.get('REMORA_SCHEMA');
55
+ (0, Affirm_1.default)(internalSchema, `Missing "REMORA_SCHEMA" on project settings (needed due to "${producer.name}" wanting to create a view)`);
56
56
  const sql = SQLCompiler_1.default.compileProducer(producer, source);
57
57
  const vSQL = `CREATE OR REPLACE VIEW "${internalSchema}"."${SQLUtils_1.default.viewName(producer.name)}" AS ${sql}`;
58
58
  yield driver.execute(vSQL);
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class SecretManagerClass {
4
+ constructor() {
5
+ this.replaceSecret = (value) => {
6
+ if (!value || value.length <= 2 || !value.startsWith('{') || !value.endsWith('}'))
7
+ return value;
8
+ const parsedValue = value.slice(1, value.length - 1);
9
+ return process.env[parsedValue];
10
+ };
11
+ }
12
+ }
13
+ const SecretManager = new SecretManagerClass();
14
+ exports.default = SecretManager;
@@ -121,7 +121,7 @@ class ValidatorClass {
121
121
  const groupingFields = fields.filter(x => x.grouping);
122
122
  if (groupingFields.length > 1)
123
123
  errors.push(`There can't be 2 fields with grouping defined at the same level (${groupingFields.map(x => x.key).join(', ')}). Level: ${level}`);
124
- groupingFields.forEach(field => {
124
+ groupingFields.forEach((field) => {
125
125
  if (field.grouping)
126
126
  errors = [...errors, ...validateGroupingLevels(field.grouping.subFields, level + 1)];
127
127
  });
@@ -136,10 +136,11 @@ class ValidatorClass {
136
136
  }
137
137
  for (let i = 0; i < consumer.outputs.length; i++) {
138
138
  const output = consumer.outputs[i];
139
- if (output.format === 'SQL' && output.accellerated && output.direct)
140
- errors.push(`An output SQL cannot be both direct and accelerated (output: ${output.format})`);
141
- if ((output.format === 'CSV' || output.format === 'JSON' || output.format === 'PARQUET') && !output.exportDestination)
142
- errors.push(`A static file output must have an export destination set (${output.format})`);
139
+ const format = output.format.toUpperCase();
140
+ if (format === 'SQL' && output.accellerated && output.direct)
141
+ errors.push(`An output SQL cannot be both direct and accelerated (output: ${format})`);
142
+ if ((format === 'CSV' || format === 'JSON' || format === 'PARQUET') && !output.exportDestination)
143
+ errors.push(`A static file output must have an export destination set (${format})`);
143
144
  }
144
145
  }
145
146
  catch (e) {
@@ -28,7 +28,7 @@ class ConsumerEngineClass {
28
28
  this.compile = (consumer) => {
29
29
  var _a, _b;
30
30
  (0, Affirm_1.default)(consumer, `Invalid consumer`);
31
- const availableColumns = consumer.producers.flatMap((cProd) => {
31
+ const availableColumns = consumer.producers.flatMap(cProd => {
32
32
  var _a, _b;
33
33
  const producer = Environment_1.default.getProducer(cProd.name);
34
34
  if (!producer) {
@@ -63,7 +63,7 @@ class ConsumerEngineClass {
63
63
  // TODO: replace with the new funcitons in the consumermanager to reduce diplicate code
64
64
  if (field.key === '*') {
65
65
  const from = (_a = field.from) !== null && _a !== void 0 ? _a : (consumer.producers.length === 1 ? consumer.producers[0].name : null);
66
- availableColumns.filter(x => x.owner === from).forEach((col) => {
66
+ availableColumns.filter(x => x.owner === from).forEach(col => {
67
67
  col.consumerKey = col.nameInProducer;
68
68
  col.consumerAlias = col.nameInProducer;
69
69
  selectedColumns.push(col);
@@ -104,8 +104,8 @@ class ConsumerEngineClass {
104
104
  case 'create-materialized-view': {
105
105
  const sql = SQLCompiler_1.default.compileConsumer(consumer);
106
106
  (0, Affirm_1.default)(sql, `Invalid SQL from deployment compilation for consumer "${consumer.name}"`);
107
- const internalSchema = Environment_1.default.get('schema');
108
- (0, Affirm_1.default)(internalSchema, `Invalid schema set on the authentication for source "${source.name}"`);
107
+ const internalSchema = Environment_1.default.get('REMORA_SCHEMA');
108
+ (0, Affirm_1.default)(internalSchema, `Missing "REMORA_SCHEMA" on project settings (needed due to "${consumer.name}" wanting to create a view)`);
109
109
  // TODO When I want to update a materialize view there is no way except killing it and recreating it. The problem is that: 1) it is not said that it can be deleted since that materialize view could have some dependencies 2) we should find a way to update it without it going completely offline.
110
110
  const mvSQL = `
111
111
  DROP MATERIALIZED VIEW IF EXISTS "${internalSchema}"."${SQLUtils_1.default.acceleratedViewName(consumer.name)}";
@@ -116,8 +116,8 @@ class ConsumerEngineClass {
116
116
  case 'create-view': {
117
117
  const sql = SQLCompiler_1.default.compileConsumer(consumer);
118
118
  (0, Affirm_1.default)(sql, `Invalid SQL from deployment compilation for consumer "${consumer.name}"`);
119
- const internalSchema = Environment_1.default.get('schema');
120
- (0, Affirm_1.default)(internalSchema, `Invalid schema set on the authentication for source "${source.name}"`);
119
+ const internalSchema = Environment_1.default.get('REMORA_SCHEMA');
120
+ (0, Affirm_1.default)(internalSchema, `Missing "REMORA_SCHEMA" on project settings (needed due to "${consumer.name}" wanting to create a view)`);
121
121
  const vSQL = `CREATE OR REPLACE VIEW "${internalSchema}"."${SQLUtils_1.default.sanitizeName(consumer.name)}" AS ${sql}`;
122
122
  yield driver.execute(vSQL);
123
123
  break;
@@ -145,14 +145,14 @@ class ConsumerEngineClass {
145
145
  (0, Affirm_1.default)(consumer, `Invalid consumer`);
146
146
  const compiled = this.compile(consumer);
147
147
  const outDimensions = compiled.map(x => {
148
- var _a;
148
+ var _a, _b, _c, _d, _e, _f, _g, _h;
149
149
  return ({
150
150
  name: (_a = x.consumerAlias) !== null && _a !== void 0 ? _a : x.consumerKey,
151
- type: x.dimension.type,
152
- classification: x.dimension.classification,
153
- description: x.dimension.description,
154
- mask: x.dimension.mask,
155
- pk: x.dimension.pk
151
+ type: (_b = x.dimension) === null || _b === void 0 ? void 0 : _b.type,
152
+ classification: (_c = x.dimension) === null || _c === void 0 ? void 0 : _c.classification,
153
+ description: (_e = (_d = x.dimension) === null || _d === void 0 ? void 0 : _d.description) !== null && _e !== void 0 ? _e : (_f = x.measure) === null || _f === void 0 ? void 0 : _f.description,
154
+ mask: (_g = x.dimension) === null || _g === void 0 ? void 0 : _g.mask,
155
+ pk: (_h = x.dimension) === null || _h === void 0 ? void 0 : _h.pk
156
156
  });
157
157
  });
158
158
  return {
@@ -56,7 +56,7 @@ class ExecutionPlannerClas {
56
56
  // TODO: how to handle pagination of SQL results?
57
57
  const engineClass = this.getEngineClass(producerEngine);
58
58
  for (const output of consumer.outputs) {
59
- switch (output.format) {
59
+ switch (output.format.toUpperCase()) {
60
60
  case 'JSON': {
61
61
  if (engineClass === 'file' && Algo_1.default.hasVal(options))
62
62
  plan.push({ type: 'apply-execution-request-to-result' });
@@ -60,7 +60,7 @@ class FileExporterClass {
60
60
  let exportData = null;
61
61
  let extension = null;
62
62
  // build the actual file in the requested format
63
- switch (output.format) {
63
+ switch (output.format.toUpperCase()) {
64
64
  case 'CSV': {
65
65
  const lines = [];
66
66
  const keys = Object.keys(data[0]);
@@ -53,8 +53,8 @@ class SQLCompilerClass {
53
53
  return sql;
54
54
  }
55
55
  else {
56
- const internalSchema = Environment_1.default.get('schema');
57
- (0, Affirm_1.default)(internalSchema, `Invalid schema set on the authentication for source "${source.name}"`);
56
+ const internalSchema = Environment_1.default.get('REMORA_SCHEMA');
57
+ (0, Affirm_1.default)(internalSchema, `Missing "REMORA_SCHEMA" on project settings (needed due to "${producer.name}" wanting to create a view)`);
58
58
  return `CREATE OR REPLACE VIEW "${internalSchema}"."${producer.name}" AS ${sql}`;
59
59
  }
60
60
  };
@@ -70,8 +70,8 @@ class SQLCompilerClass {
70
70
  return this.compileProducer(producer, source);
71
71
  }
72
72
  else {
73
- const internalSchema = Environment_1.default.get('schema');
74
- (0, Affirm_1.default)(internalSchema, `Invalid schema set on the authentication for source "${source.name}"`);
73
+ const internalSchema = Environment_1.default.get('REMORA_SCHEMA');
74
+ (0, Affirm_1.default)(internalSchema, `Missing "REMORA_SCHEMA" on project settings (needed due to "${producer.name}" wanting to create a view)`);
75
75
  return `SELECT * FROM "${internalSchema}"."${producer.name}"`;
76
76
  }
77
77
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@forzalabs/remora",
3
- "version": "0.0.12",
4
- "description": "Your Next.js and Node.js application with TypeScript CLI",
3
+ "version": "0.0.13",
4
+ "description": "A powerful CLI tool for seamless data translation.",
5
5
  "main": "index.js",
6
6
  "private": false,
7
7
  "bin": {