@miso.ai/server-sdk 0.6.6-beta.1 → 0.6.6-beta.11

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/cli/delete.js CHANGED
@@ -34,6 +34,7 @@ function build(yargs) {
34
34
  }
35
35
 
36
36
  const run = type => async ({
37
+ env,
37
38
  key,
38
39
  server,
39
40
  param: params,
@@ -49,7 +50,7 @@ const run = type => async ({
49
50
  loglevel = (debug || progress) ? log.DEBUG : loglevel;
50
51
  logFormat = progress ? logger.FORMAT.PROGRESS : logFormat;
51
52
 
52
- const client = new MisoClient({ key, server, debug });
53
+ const client = new MisoClient({ env, key, server, debug });
53
54
 
54
55
  const deleteStream = client.api[type].deleteStream({
55
56
  name,
package/cli/get.js CHANGED
@@ -4,12 +4,13 @@ import { formatError } from './utils.js';
4
4
  const build = yargs => yargs;
5
5
 
6
6
  const run = type => async ({
7
+ env,
7
8
  key,
8
9
  server,
9
10
  id,
10
11
  debug,
11
12
  }) => {
12
- const client = new MisoClient({ key, server, debug });
13
+ const client = new MisoClient({ env, key, server, debug });
13
14
  try {
14
15
  const entity = await client.api[type].get(id);
15
16
  console.log(JSON.stringify(entity));
@@ -15,8 +15,8 @@ function build(yargs) {
15
15
  });
16
16
  }
17
17
 
18
- async function run({ query, fq, fl, rows, answer, key, server, debug }) {
19
- const client = new MisoClient({ key, server, debug });
18
+ async function run({ query, fq, fl, rows, answer, env, key, server, debug }) {
19
+ const client = new MisoClient({ env, key, server, debug });
20
20
  const { products } = await client.api.ask.search({ q: query, fq, fl, rows, answer });
21
21
  const readStream = Readable.from(products);
22
22
  const outputStream = new stream.OutputStream();
package/cli/ids-diff.js CHANGED
@@ -25,6 +25,7 @@ function build(yargs) {
25
25
  };
26
26
 
27
27
  const run = type => async ({
28
+ env,
28
29
  key,
29
30
  server,
30
31
  output,
@@ -34,7 +35,7 @@ const run = type => async ({
34
35
  }) => {
35
36
  output = output || (plus ? 'plus' : minus ? 'minus' : undefined);
36
37
 
37
- const client = new MisoClient({ key, server, debug });
38
+ const client = new MisoClient({ env, key, server, debug });
38
39
  const misoIds = await client.api[type].ids();
39
40
 
40
41
  const diffStream = new stream.DiffStream(misoIds, { output });
package/cli/ids.js CHANGED
@@ -19,12 +19,13 @@ const build = type => yargs => {
19
19
  };
20
20
 
21
21
  const run = type => async ({
22
+ env,
22
23
  key,
23
24
  server,
24
25
  type: recordType,
25
26
  debug,
26
27
  }) => {
27
- const client = new MisoClient({ key, server, debug });
28
+ const client = new MisoClient({ env, key, server, debug });
28
29
  let ids;
29
30
  try {
30
31
  const options = recordType ? { type: recordType } : {};
package/cli/index.js CHANGED
@@ -7,6 +7,7 @@ import upload from './upload.js';
7
7
  import del from './delete.js';
8
8
  import ids from './ids.js';
9
9
  import transform from './transform.js';
10
+ import mergeLocal from './merge-local.js';
10
11
  import status from './status.js';
11
12
  import get from './get.js';
12
13
  import search from './search.js';
@@ -70,6 +71,7 @@ yargs.build(yargs => {
70
71
  .command(users)
71
72
  .command(experiments)
72
73
  .command(transform)
74
+ .command(mergeLocal)
73
75
  .command(search)
74
76
  .command(hybridSearch)
75
77
  .version(MisoClient.version);
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env node
2
+ import 'dotenv/config';
3
+ import { join } from 'path';
4
+ import { createReadStream } from 'fs';
5
+ import { createGunzip } from 'zlib';
6
+ import { pipeline } from 'stream/promises';
7
+ import { chain } from 'stream-chain';
8
+ import split2 from 'split2';
9
+ import { stream, trimObj } from '@miso.ai/server-commons';
10
+
11
+ const PWD = process.env.PWD;
12
+
13
+ process.stdout.on('error', err => err.code == 'EPIPE' && process.exit(0));
14
+
15
+ function build(yargs) {
16
+ return yargs
17
+ .positional('file1', {
18
+ describe: 'First record file',
19
+ type: 'string',
20
+ demandOption: true,
21
+ })
22
+ .positional('file2', {
23
+ describe: 'Second record file',
24
+ type: 'string',
25
+ })
26
+ .option('join-mode', {
27
+ alias: 'm',
28
+ describe: 'Join mode',
29
+ type: 'string',
30
+ default: 'merge',
31
+ choices: ['merge', 'rewrite-meta', 'remeta'],
32
+ })
33
+ .option('join-function', {
34
+ alias: 'f',
35
+ describe: 'Join function',
36
+ type: 'string',
37
+ })
38
+ .option('stdin', {
39
+ alias: 'i',
40
+ describe: 'Read the first stream from stdin',
41
+ type: 'boolean',
42
+ default: false,
43
+ });
44
+ }
45
+
46
+ async function run({ file1, file2, stdin, joinMode, joinFunction }) {
47
+ if (stdin) {
48
+ file2 = file1;
49
+ file1 = undefined;
50
+ } else if (!file2) {
51
+ throw new Error('Second file is required');
52
+ }
53
+ const stream1 = chain([
54
+ stdin ? process.stdin : createReadStream(file1),
55
+ ...(file1 && file1.endsWith('.gz')) ? [createGunzip()] : [],
56
+ split2(JSON.parse),
57
+ ]);
58
+ const stream2 = chain([
59
+ createReadStream(file2),
60
+ ...(file2 && file2.endsWith('.gz')) ? [createGunzip()] : [],
61
+ split2(JSON.parse),
62
+ ]);
63
+ await pipeline(
64
+ stream.joinStreams([stream1, stream2], await getJoinFunction(joinMode, joinFunction)),
65
+ new stream.OutputStream(),
66
+ );
67
+ }
68
+
69
+ async function getJoinFunction(joinMode, joinFunction) {
70
+ if (joinFunction) {
71
+ try {
72
+ const fn = await import(join(PWD, joinFunction));
73
+ if (!fn.default) {
74
+ throw new Error('Join function must have a default export');
75
+ }
76
+ return fn.default;
77
+ } catch (e) {
78
+ console.error(`Failed to load join function ${joinFunction}:`, e);
79
+ process.exit(1);
80
+ }
81
+ }
82
+ switch (joinMode) {
83
+ case 'merge':
84
+ return merge;
85
+ case 'rewrite-meta':
86
+ case 'remeta':
87
+ return rewriteMeta;
88
+ default:
89
+ throw new Error(`Unsupported join mode: ${joinMode}`);
90
+ }
91
+ }
92
+
93
+ function merge(record1, record2) {
94
+ assertSameProductId(record1, record2);
95
+ return trimObj({
96
+ ...record1,
97
+ ...record2,
98
+ custom_attributes: trimObj({
99
+ ...(record1 && record1.custom_attributes),
100
+ ...(record2 && record2.custom_attributes),
101
+ }),
102
+ });
103
+ }
104
+
105
+ function rewriteMeta(record1, record2) {
106
+ assertSameProductId(record1, record2);
107
+ const { description, html, children } = record1;
108
+ const { description: _0, html: _1, children: _2, ...rest } = record2;
109
+ return trimObj({
110
+ ...rest,
111
+ description,
112
+ html,
113
+ children,
114
+ });
115
+ }
116
+
117
+ function assertSameProductId(record1, record2) {
118
+ if (record1.product_id !== record2.product_id) {
119
+ throw new Error(`Product IDs do not match: ${record1.product_id} and ${record2.product_id}`);
120
+ }
121
+ }
122
+
123
+ export default {
124
+ command: 'merge-local <file1> [file2]',
125
+ alias: ['patch-local'],
126
+ description: 'Apply patch records from file onto input record stream',
127
+ builder: build,
128
+ handler: run,
129
+ };
package/cli/merge.js CHANGED
@@ -23,6 +23,7 @@ function build(yargs) {
23
23
  }
24
24
 
25
25
  const run = type => async ({
26
+ env,
26
27
  key,
27
28
  server,
28
29
  file,
@@ -32,7 +33,7 @@ const run = type => async ({
32
33
  }) => {
33
34
  const mergeFn = await getMergeFn(file);
34
35
  const records = await buildBaseRecords(base);
35
- const client = new MisoClient({ key, server, debug });
36
+ const client = new MisoClient({ env, key, server, debug });
36
37
  const mergeStream = client.api[type].mergeStream({ ...options, mergeFn, records });
37
38
  const outputStream = new stream.OutputStream({ objectMode: true });
38
39
  await stream.pipeline(
package/cli/search.js CHANGED
@@ -10,8 +10,8 @@ function build(yargs) {
10
10
  });
11
11
  }
12
12
 
13
- async function run({ query, fq, fl, rows, key, server, debug }) {
14
- const client = new MisoClient({ key, server, debug });
13
+ async function run({ query, fq, fl, rows, env, key, server, debug }) {
14
+ const client = new MisoClient({ env, key, server, debug });
15
15
  const records = await client.api.search.search({ q: query, fq, fl, rows });
16
16
  const readStream = Readable.from(records);
17
17
  const outputStream = new stream.OutputStream();
package/cli/status.js CHANGED
@@ -7,12 +7,13 @@ const build = type => yargs => {
7
7
  };
8
8
 
9
9
  const run = type => async ({
10
+ env,
10
11
  key,
11
12
  server,
12
13
  taskId,
13
14
  debug,
14
15
  }) => {
15
- const client = new MisoClient({ key, server, debug });
16
+ const client = new MisoClient({ env, key, server, debug });
16
17
  if (taskId) {
17
18
  runOne(client, type, taskId);
18
19
  } else {
package/cli/upload.js CHANGED
@@ -46,6 +46,7 @@ function build(yargs) {
46
46
  }
47
47
 
48
48
  const run = type => async ({
49
+ env,
49
50
  key,
50
51
  server,
51
52
  param: params,
@@ -66,7 +67,7 @@ const run = type => async ({
66
67
  loglevel = (debug || progress) ? log.DEBUG : loglevel;
67
68
  logFormat = progress ? logger.FORMAT.PROGRESS : logFormat;
68
69
 
69
- const client = new MisoClient({ key, server, debug });
70
+ const client = new MisoClient({ env, key, server, debug });
70
71
 
71
72
  const uploadStreamObjectMode = lenient;
72
73
 
package/cli/utils.js CHANGED
@@ -6,6 +6,10 @@ export function buildForApi(yargs) {
6
6
  alias: ['k', 'api-key'],
7
7
  describe: 'API key',
8
8
  })
9
+ .option('env', {
10
+ describe: 'Environment',
11
+ type: 'string',
12
+ })
9
13
  .option('server', {
10
14
  alias: ['api-server'],
11
15
  describe: 'API server',
@@ -19,8 +23,7 @@ export function buildForApi(yargs) {
19
23
  .option('debug', {
20
24
  describe: 'Set log level to debug',
21
25
  type: 'boolean',
22
- })
23
- .demandOption(['key'], 'API key is required.');
26
+ });
24
27
  }
25
28
 
26
29
  export function buildForSearch(yargs) {
package/package.json CHANGED
@@ -16,12 +16,12 @@
16
16
  "simonpai <simon.pai@askmiso.com>"
17
17
  ],
18
18
  "dependencies": {
19
- "@miso.ai/server-commons": "0.6.6-beta.1",
19
+ "@miso.ai/server-commons": "0.6.6-beta.11",
20
20
  "axios": "^1.6.2",
21
21
  "axios-retry": "^4.5.0",
22
22
  "dotenv": "^16.0.1",
23
23
  "split2": "^4.1.0",
24
24
  "yargs": "^17.5.1"
25
25
  },
26
- "version": "0.6.6-beta.1"
26
+ "version": "0.6.6-beta.11"
27
27
  }
@@ -37,6 +37,7 @@ async function recoverValidRecords(client, type, records, options, response) {
37
37
  return; // still fail, never mind...
38
38
  }
39
39
  response.recovered = {
40
+ product_ids: validRecords.map(record => record.product_id),
40
41
  records: validRecords.length,
41
42
  bytes: validPayload.length * 2,
42
43
  };
package/src/client.js CHANGED
@@ -28,6 +28,7 @@ function normalizeOptions(options) {
28
28
  if (typeof options === 'string') {
29
29
  options = { key: options };
30
30
  }
31
+ options.key = getApiKeyFromEnv(options.env, options.key);
31
32
  if (!options.key || typeof options.key !== 'string') {
32
33
  throw new Error(`API key is required.`);
33
34
  }
@@ -35,3 +36,10 @@ function normalizeOptions(options) {
35
36
 
36
37
  return options;
37
38
  }
39
+
40
+ function getApiKeyFromEnv(env, key) {
41
+ if (!env) {
42
+ return key;
43
+ }
44
+ return process.env[`MISO_${env.toUpperCase()}_API_KEY`] || undefined;
45
+ }
@@ -65,7 +65,6 @@ export default class ApiSink extends sink.BpsSink {
65
65
  }
66
66
 
67
67
  // keep track of service stats on successful calls
68
- // TODO: handle recovered records?
69
68
  if (!data.errors) {
70
69
  this._serviceStats.track({ records, bytes, took: data.took });
71
70
  }
package/src/version.js CHANGED
@@ -1 +1 @@
1
- export default '0.6.6-beta.1';
1
+ export default '0.6.6-beta.11';