kourou 0.25.0 → 0.25.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/README.md CHANGED
@@ -26,7 +26,7 @@ $ npm install -g kourou
26
26
  $ kourou COMMAND
27
27
  running command...
28
28
  $ kourou (-v|--version|version)
29
- kourou/0.25.0 linux-x64 node-v16.15.0
29
+ kourou/0.25.2 linux-x64 node-v14.20.0
30
30
  $ kourou --help [COMMAND]
31
31
  USAGE
32
32
  $ kourou COMMAND
@@ -365,7 +365,7 @@ ARGUMENTS
365
365
  DESTINATION Directory to scaffold the app
366
366
 
367
367
  OPTIONS
368
- --flavor=flavor [default: generic] Template flavor ("generic", "iot-platform", "iot-console", "iot-platform").
368
+ --flavor=flavor [default: generic] Template flavor ("generic", "iot-backend", "iot-console").
369
369
  Those can be found here: https://github.com/kuzzleio/project-templates
370
370
 
371
371
  --help show CLI help
@@ -506,6 +506,9 @@ OPTIONS
506
506
  --ssl
507
507
  Use SSL to connect to Kuzzle
508
508
 
509
+ --type=type
510
+ [default: all] Type of the export: all, mappings, data
511
+
509
512
  --username=username
510
513
  [default: anonymous] Kuzzle username (local strategy)
511
514
 
@@ -547,7 +550,7 @@ _See code: [src/commands/collection/import.ts](src/commands/collection/import.ts
547
550
 
548
551
  ## `kourou collection:migrate SCRIPT PATH`
549
552
 
550
- Migrate a collection
553
+ Migrate a collection by transforming documents from a dump file and importing them into Kuzzle
551
554
 
552
555
  ```
553
556
  USAGE
@@ -938,6 +941,8 @@ OPTIONS
938
941
 
939
942
  --ssl Use SSL to connect to Kuzzle
940
943
 
944
+ --type=type [default: all] Type of the export: all, mappings, data
945
+
941
946
  --username=username [default: anonymous] Kuzzle username (local strategy)
942
947
 
943
948
  EXAMPLES
@@ -35,7 +35,7 @@ AppScaffold.flags = {
35
35
  help: command_1.flags.help(),
36
36
  flavor: command_1.flags.string({
37
37
  default: "generic",
38
- description: `Template flavor ("generic", "iot-platform", "iot-console", "iot-platform").
38
+ description: `Template flavor ("generic", "iot-backend", "iot-console").
39
39
  Those can be found here: https://github.com/kuzzleio/project-templates`,
40
40
  }),
41
41
  };
@@ -20,6 +20,7 @@ export default class CollectionExport extends Kommand {
20
20
  format: flags.IOptionFlag<string>;
21
21
  fields: flags.IOptionFlag<string | undefined>;
22
22
  scrollTTL: flags.IOptionFlag<string>;
23
+ type: flags.IOptionFlag<string>;
23
24
  };
24
25
  static args: {
25
26
  name: string;
@@ -22,10 +22,16 @@ class CollectionExport extends common_1.Kommand {
22
22
  }
23
23
  const countAll = await this.sdk.document.count(this.args.index, this.args.collection);
24
24
  const count = await this.sdk.document.count(this.args.index, this.args.collection, { query });
25
- this.logInfo(`Dumping ${count} of ${countAll} documents from collection "${this.args.index}:${this.args.collection}" in ${exportPath} ...`);
25
+ this.logInfo(`Dumping collection "${this.args.index}:${this.args.collection}" in ${exportPath} ...`);
26
26
  fs_1.default.mkdirSync(exportPath, { recursive: true });
27
- await (0, dump_collection_1.dumpCollectionMappings)(this.sdk, this.args.index, this.args.collection, exportPath, this.flags.format);
28
- await (0, dump_collection_1.dumpCollectionData)(this.sdk, this.args.index, this.args.collection, Number(this.flags["batch-size"]), exportPath, query, this.flags.format, fields, this.flags.scrollTTL);
27
+ if (this.flags.type === "all" || this.flags.type === "mappings") {
28
+ this.logInfo(`Dumping collection mappings ...`);
29
+ await (0, dump_collection_1.dumpCollectionMappings)(this.sdk, this.args.index, this.args.collection, exportPath, this.flags.format);
30
+ }
31
+ if (this.flags.type === "all" || this.flags.type === "data") {
32
+ this.logInfo(`Dumping collection ${count} of ${countAll} documents ...`);
33
+ await (0, dump_collection_1.dumpCollectionData)(this.sdk, this.args.index, this.args.collection, Number(this.flags["batch-size"]), exportPath, query, this.flags.format, fields, this.flags.scrollTTL);
34
+ }
29
35
  this.logOk(`Collection ${this.args.index}:${this.args.collection} dumped`);
30
36
  }
31
37
  }
@@ -60,6 +66,9 @@ exportable fields in the mapping will be exported.`,
60
66
  description: `The scroll TTL option to pass to the dump operation (which performs a document.search under the hood),
61
67
  expressed in ms format, e.g. '2s', '1m', '3h'.`,
62
68
  default: "20s",
69
+ }), type: command_1.flags.string({
70
+ description: "Type of the export: all, mappings, data",
71
+ default: "all",
63
72
  }) }, kuzzle_1.kuzzleFlags), { protocol: command_1.flags.string({
64
73
  description: "Kuzzle protocol (http or websocket)",
65
74
  default: "ws",
@@ -25,7 +25,7 @@ class CollectionMigrate extends common_1.Kommand {
25
25
  }
26
26
  exports.default = CollectionMigrate;
27
27
  CollectionMigrate.keepAuth = true;
28
- CollectionMigrate.description = "Migrate a collection";
28
+ CollectionMigrate.description = "Migrate a collection by transforming documents from a dump file and importing them into Kuzzle";
29
29
  CollectionMigrate.flags = Object.assign(Object.assign({ help: command_1.flags.help({}), "batch-size": command_1.flags.string({
30
30
  description: "Maximum batch size (see limits.documentsWriteCount config)",
31
31
  default: "200",
@@ -5,6 +5,7 @@ export default class IndexExport extends Kommand {
5
5
  static description: string;
6
6
  static flags: {
7
7
  protocol: flags.IOptionFlag<string>;
8
+ type: flags.IOptionFlag<string>;
8
9
  host: flags.IOptionFlag<string>;
9
10
  port: flags.IOptionFlag<string>;
10
11
  ssl: import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
@@ -19,11 +19,18 @@ class IndexExport extends common_1.Kommand {
19
19
  const { collections } = await this.sdk.collection.list(this.args.index);
20
20
  for (const collection of collections) {
21
21
  try {
22
- if (collection.type !== "realtime") {
22
+ if (collection.type === "realtime") {
23
+ continue;
24
+ }
25
+ if (this.flags.type === "all" || this.flags.type === "mappings") {
26
+ this.logInfo(`Dumping collection "${collection.name}" mappings ...`);
23
27
  await (0, dump_collection_1.dumpCollectionMappings)(this.sdk, this.args.index, collection.name, exportPath, this.flags.format);
28
+ }
29
+ if (this.flags.type === "all" || this.flags.type === "data") {
30
+ this.logInfo(`Dumping collection "${collection.name}" documents ...`);
24
31
  await (0, dump_collection_1.dumpCollectionData)(this.sdk, this.args.index, collection.name, Number(this.flags["batch-size"]), exportPath, query, this.flags.format, this.flags.scrollTTL);
25
- cli_ux_1.default.action.stop();
26
32
  }
33
+ cli_ux_1.default.action.stop();
27
34
  }
28
35
  catch (error) {
29
36
  this.logKo(`Error when exporting collection "${collection.name}": ${error}`);
@@ -53,6 +60,9 @@ expressed in ms format, e.g. '2s', '1m', '3h'.`,
53
60
  }) }, kuzzle_1.kuzzleFlags), { protocol: command_1.flags.string({
54
61
  description: "Kuzzle protocol (http or websocket)",
55
62
  default: "ws",
63
+ }), type: command_1.flags.string({
64
+ description: "Type of the export: all, mappings, data",
65
+ default: "all",
56
66
  }) });
57
67
  IndexExport.args = [{ name: "index", description: "Index name", required: true }];
58
68
  IndexExport.examples = [
@@ -20,10 +20,6 @@ class PaasLogin extends PaasKommand_1.PaasKommand {
20
20
  await this.authenticateNPM(username, password);
21
21
  return;
22
22
  }
23
- if (this.flags.only_npm) {
24
- await this.authenticateNPM(username, password);
25
- return;
26
- }
27
23
  await this.initPaasClient({ username, password });
28
24
  const apiKey = await this.paas.auth.createApiKey("Kourou PaaS API Key");
29
25
  this.createProjectCredentials(apiKey);
@@ -53,15 +49,19 @@ class PaasLogin extends PaasKommand_1.PaasKommand {
53
49
  password,
54
50
  }),
55
51
  };
56
- const response = await (0, node_fetch_1.default)(`https://packages.paas.kuzzle.io/-/user/org.couchdb.user:${username}`, options);
57
- const { token } = await response.json();
52
+ const response = await (0, node_fetch_1.default)(`https://${this.packagesHost}/-/user/org.couchdb.user:${username}`, options);
53
+ const json = await response.json();
54
+ if (response.status !== 201) {
55
+ throw new Error(json.error);
56
+ }
57
+ const { token } = json;
58
58
  (0, child_process_1.spawnSync)("npm", [
59
59
  "config",
60
60
  "set",
61
61
  "@kuzzleio:registry",
62
- "https://packages.paas.kuzzle.io",
62
+ `https://${this.packagesHost}`,
63
63
  ], { stdio: "inherit" });
64
- (0, child_process_1.spawnSync)("npm", ["set", "//packages.paas.kuzzle.io/:_authToken", token], {
64
+ (0, child_process_1.spawnSync)("npm", ["set", `//${this.packagesHost}/:_authToken`, token], {
65
65
  stdio: "inherit",
66
66
  });
67
67
  }
@@ -15,7 +15,15 @@ class PaasLogs extends PaasKommand_1.PaasKommand {
15
15
  /**
16
16
  * Allowed colors for pod names.
17
17
  */
18
- this.allColors = [chalk_1.default.red, chalk_1.default.green, chalk_1.default.yellow, chalk_1.default.blue, chalk_1.default.magenta, chalk_1.default.cyan, chalk_1.default.gray];
18
+ this.allColors = [
19
+ chalk_1.default.red,
20
+ chalk_1.default.green,
21
+ chalk_1.default.yellow,
22
+ chalk_1.default.blue,
23
+ chalk_1.default.magenta,
24
+ chalk_1.default.cyan,
25
+ chalk_1.default.gray,
26
+ ];
19
27
  /**
20
28
  * Available colors for pod names.
21
29
  */
@@ -34,8 +42,12 @@ class PaasLogs extends PaasKommand_1.PaasKommand {
34
42
  this.logInfo(`Logged as "${user._id}" for project "${this.flags.project || this.getProject()}"`);
35
43
  const separator = "\t";
36
44
  // Parse the time arguments
37
- const since = this.flags.since ? chrono.parseDate(this.flags.since).toISOString() : undefined;
38
- const until = this.flags.until ? chrono.parseDate(this.flags.until).toISOString() : undefined;
45
+ const since = this.flags.since
46
+ ? chrono.parseDate(this.flags.since).toISOString()
47
+ : undefined;
48
+ const until = this.flags.until
49
+ ? chrono.parseDate(this.flags.until).toISOString()
50
+ : undefined;
39
51
  // Perform the streamed request
40
52
  const incomingMessage = await this.paas.queryHttpStream({
41
53
  controller: "application",
@@ -59,18 +71,24 @@ class PaasLogs extends PaasKommand_1.PaasKommand {
59
71
  // Display the response
60
72
  for (var lineStream_1 = (0, tslib_1.__asyncValues)(lineStream), lineStream_1_1; lineStream_1_1 = await lineStream_1.next(), !lineStream_1_1.done;) {
61
73
  const line = lineStream_1_1.value;
62
- // Parse the data
63
- const data = JSON.parse(line);
64
- // Exclude logs that are empty or that are not from a pod
65
- if (!data.content || !data.podName) {
66
- continue;
74
+ try {
75
+ const data = JSON.parse(line);
76
+ // Exclude logs that are empty or that are not from a pod
77
+ if (!data.content || !data.podName) {
78
+ continue;
79
+ }
80
+ // Get the pod color
81
+ const podColor = this.getPodColor(data.podName);
82
+ // Display the log
83
+ const timestamp = this.flags.timestamp
84
+ ? `[${new Date(data.timeStamp).toLocaleString()}] `
85
+ : "";
86
+ const name = podColor(`${data.podName}${separator}`);
87
+ this.log(`${timestamp}${name}| ${data.content}`);
88
+ }
89
+ catch (error) {
90
+ this.logKo(`Error while parsing log: ${error} (Received: "${line}")`);
67
91
  }
68
- // Get the pod color
69
- const podColor = this.getPodColor(data.podName);
70
- // Display the log
71
- const timestamp = this.flags.timestamp ? `[${new Date(data.timeStamp).toLocaleString()}] ` : "";
72
- const name = podColor(`${data.podName}${separator}`);
73
- this.log(`${timestamp}${name}| ${data.content}`);
74
92
  }
75
93
  }
76
94
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -101,13 +119,15 @@ class PaasLogs extends PaasKommand_1.PaasKommand {
101
119
  }
102
120
  getNumberOfSpaces(names, currentName) {
103
121
  const end = 10;
104
- let max = { name: '', length: 0 };
122
+ let max = { name: "", length: 0 };
105
123
  for (const name of names) {
106
124
  if (max.length < name.length) {
107
125
  max = { name: name, length: name.length };
108
126
  }
109
127
  }
110
- return currentName === max.name ? end : end + (max.length - currentName.length);
128
+ return currentName === max.name
129
+ ? end
130
+ : end + (max.length - currentName.length);
111
131
  }
112
132
  /**
113
133
  * Returns the color to use for a pod name.
@@ -11,6 +11,7 @@ export declare class PaasKommand extends Kommand {
11
11
  protected host: string;
12
12
  protected port: number;
13
13
  protected ssl: any;
14
+ protected packagesHost: string;
14
15
  protected paas: KuzzleSDK;
15
16
  initPaasClient(credentials: PaaSClientCredentials): Promise<void>;
16
17
  fileProjectCredentials(project: string): string;
@@ -18,6 +18,9 @@ class PaasKommand extends common_1.Kommand {
18
18
  this.ssl = process.env.KUZZLE_PAAS_SSL
19
19
  ? JSON.parse(process.env.KUZZLE_PAAS_SSL)
20
20
  : true;
21
+ this.packagesHost = process.env.KUZZLE_PAAS_PACKAGES_HOST
22
+ ? process.env.KUZZLE_PAAS_PACKAGES_HOST
23
+ : "packages.paas.kuzzle.io";
21
24
  // Instantiate a dummy SDK to avoid the this.paas? notation everywhere -_-
22
25
  this.paas = new kuzzle_1.KuzzleSDK({});
23
26
  }
@@ -81,6 +81,7 @@ class AbstractDumper {
81
81
  * @returns a promise resolving when the dump is finished.
82
82
  */
83
83
  async dump() {
84
+ fs_1.default.mkdirSync(this.collectionDir, { recursive: true });
84
85
  this.filename = path_1.default.join(this.collectionDir, `documents.${this.fileExtension}`);
85
86
  this.writeStream = fs_1.default.createWriteStream(this.filename);
86
87
  const waitWrite = new Promise((resolve, reject) => this.writeStream ? this.writeStream.on("finish", resolve) : reject());
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.KuzzleSDK = exports.kuzzleFlags = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const http_1 = (0, tslib_1.__importDefault)(require("http"));
6
+ const https_1 = (0, tslib_1.__importDefault)(require("https"));
6
7
  const command_1 = require("@oclif/command");
7
8
  const kuzzle_sdk_1 = require("kuzzle-sdk");
8
9
  const SECOND = 1000;
@@ -163,14 +164,15 @@ class KuzzleSDK {
163
164
  const options = {
164
165
  method: "POST",
165
166
  headers: {
166
- "Authorization": `Bearer ${this.sdk.jwt}`,
167
+ Authorization: `Bearer ${this.sdk.jwt}`,
167
168
  "Content-Length": Buffer.byteLength(body),
168
169
  "Content-Type": "application/json",
169
170
  },
170
171
  };
171
172
  // Send the request
172
173
  return new Promise((resolve, reject) => {
173
- const req = http_1.default.request(url, options, (res) => {
174
+ const httpModule = this.ssl ? https_1.default : http_1.default;
175
+ const req = httpModule.request(url, options, (res) => {
174
176
  resolve(res);
175
177
  });
176
178
  req.on("error", reject);
@@ -6,18 +6,16 @@ const fs_1 = (0, tslib_1.__importDefault)(require("fs"));
6
6
  const chalk_1 = (0, tslib_1.__importDefault)(require("chalk"));
7
7
  const ndjson_1 = (0, tslib_1.__importDefault)(require("ndjson"));
8
8
  function handleError(log, dumpFile, error) {
9
- if (error.status === 206) {
9
+ if (error.errors) {
10
10
  const errorFile = `${dumpFile
11
11
  .split(".")
12
12
  .slice(0, -1)
13
13
  .join(".")}-errors.jsonl`;
14
14
  const writeStream = fs_1.default.createWriteStream(errorFile, { flags: "a" });
15
- const serialize = ndjson_1.default.stringify().pipe(writeStream);
16
- serialize.on("data", (line) => writeStream.write(line));
17
15
  for (const partialError of error.errors) {
18
- serialize.write(partialError);
16
+ writeStream.write(JSON.stringify(partialError) + '\n');
19
17
  }
20
- serialize.end();
18
+ writeStream.end();
21
19
  log(chalk_1.default.red(`[X] Error importing ${dumpFile}. See errors in ${errorFile}`));
22
20
  }
23
21
  else {
@@ -31,6 +29,7 @@ async function restoreCollectionData(sdk, log, batchSize, dumpFile, index, colle
31
29
  action: "mWrite",
32
30
  index: "",
33
31
  collection: "",
32
+ strict: true,
34
33
  body: {
35
34
  documents: [{}],
36
35
  },
@@ -90,8 +89,8 @@ async function restoreCollectionData(sdk, log, batchSize, dumpFile, index, colle
90
89
  mWriteRequest.body.documents = documents;
91
90
  sdk
92
91
  .query(mWriteRequest)
93
- .then(() => {
94
- total += mWriteRequest.body.documents.length;
92
+ .then((response) => {
93
+ total += response.result.successes.length;
95
94
  process.stdout.write(` ${total} documents imported`);
96
95
  process.stdout.write("\r");
97
96
  resolve(undefined);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kourou",
3
3
  "description": "The CLI that helps you manage your Kuzzle instances",
4
- "version": "0.25.0",
4
+ "version": "0.25.2",
5
5
  "author": "The Kuzzle Team <support@kuzzle.io>",
6
6
  "bin": {
7
7
  "kourou": "./bin/run"