@miso.ai/client-sdk-dev-tool 1.13.2-beta.1 → 1.14.0-beta.3

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/cjs/debug.js CHANGED
@@ -8,6 +8,12 @@ var _logs = require("./logs.js");
8
8
  const _excluded = ["groupName", "apiName", "url", "bulk"];
9
9
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
10
10
  const ID = 'std:debug';
11
+
12
+ // the item subworkflow contexts emit per item (one workflow per thread of
13
+ // the list, per message of the conversation), which floods the console.
14
+ // Muted paths stay out of the console only: they are still preserved for
15
+ // the log dump. Configurable via the `mute` option (`mute: []` shows all)
16
+ const DEFAULT_MUTE = Object.freeze(['workflow/thread-items', 'workflow/message-items']);
11
17
  class DebugPlugin {
12
18
  constructor(options = {}) {
13
19
  this._options = options;
@@ -56,6 +62,10 @@ class DebugPlugin {
56
62
  }));
57
63
  return;
58
64
  }
65
+ if (path.length === 1 && (name === 'workflow' || name === 'postworkflow')) {
66
+ this._handleClientWorkflowEvent(name, data);
67
+ return;
68
+ }
59
69
  break;
60
70
  case 'plugins':
61
71
  if (path.length === 1) {
@@ -80,7 +90,12 @@ class DebugPlugin {
80
90
  const pathname = new URL(url).pathname;
81
91
  const args = ['api', eventName];
82
92
  bulk && args.push(`(bulk ${bulk.bulkId})`);
83
- args.push(`POST ${pathname}`);
93
+
94
+ // the api helpers' fetch defaults to POST when no method is specified
95
+ const {
96
+ method = 'POST'
97
+ } = data.options || {};
98
+ args.push(`${method} ${pathname}`);
84
99
  if (groupName === 'interactions') {
85
100
  // TODO: handle multiple interactions
86
101
  const record = data.payload.data[0];
@@ -109,8 +124,18 @@ class DebugPlugin {
109
124
  }
110
125
  this._log('plugins', eventName, `${plugin.id || '(anonymous)'}`, [plugin, ...data]);
111
126
  }
127
+
128
+ // a workflow's creation events on the client follow its context: the
129
+ // workflows of a muted context (the item subworkflows) are muted as well
130
+ _handleClientWorkflowEvent(name, workflow) {
131
+ const context = workflow && workflow._context;
132
+ const silent = !!context && this._isMuted(_joinPath(_pluginComponentPath(context.meta.path)));
133
+ this._logw('client', name, workflow, {
134
+ silent
135
+ });
136
+ }
112
137
  _handlePluginSpecificEvent(pluginId, path, name, data) {
113
- this._logw([pluginId, path.join('.')], name, data);
138
+ this._logw(_pluginComponentPath([pluginId, ...path]), name, data);
114
139
  }
115
140
  _getPath(component) {
116
141
  const path = [];
@@ -119,25 +144,48 @@ class DebugPlugin {
119
144
  }
120
145
  return path.reverse();
121
146
  }
122
- _logw(path, name, data) {
147
+ _logw(path, name, data, options) {
123
148
  if (data === undefined) {
124
- this._log(path, name);
149
+ data = [];
125
150
  } else if (Array.isArray(data)) {
126
- this._log(path, name, ...data.map(_wrapObj));
151
+ data = data.map(_wrapObj);
127
152
  } else {
128
- this._log(path, name, _wrapObj(data));
153
+ data = [_wrapObj(data)];
129
154
  }
155
+ this._logp(path, name, data, options);
130
156
  }
131
157
  _log(path, name, ...data) {
132
- this._logr(_path(path), _name(name), ...data);
158
+ this._logp(path, name, data);
159
+ }
160
+ _logp(path, name, data, {
161
+ silent = false
162
+ } = {}) {
163
+ path = _joinPath(path);
164
+ this._write([_path(path), _name(name), ...data], {
165
+ silent: silent || this._isMuted(path)
166
+ });
133
167
  }
134
168
  _logr(...data) {
169
+ this._write(data);
170
+ }
171
+ _write(data, {
172
+ silent = false
173
+ } = {}) {
135
174
  const options = this._options.console || {};
136
175
  if (this._options.preserveLog) {
137
176
  this._logs._logs.push(data);
138
177
  }
178
+ if (silent) {
179
+ return;
180
+ }
139
181
  console.log(_tag(options), _style(options), ...data);
140
182
  }
183
+ _isMuted(path) {
184
+ const {
185
+ mute = DEFAULT_MUTE
186
+ } = this._options;
187
+ return mute.includes(path);
188
+ }
141
189
  }
142
190
  exports.default = DebugPlugin;
143
191
  function _tag({
@@ -154,7 +202,17 @@ function _style({
154
202
 
155
203
  // format path
156
204
  function _path(path) {
157
- return `<${typeof path === 'string' ? path : path.filter(v => v).join('/')}>`;
205
+ return `<${path}>`;
206
+ }
207
+
208
+ // the log path of a component under a plugin, off its meta path — which
209
+ // starts at the plugin ([pluginId, ...rest]): the plugins root reaches the
210
+ // plugins as subtrees, not as parents
211
+ function _pluginComponentPath(path) {
212
+ return [path[0], path.slice(1).join('.')];
213
+ }
214
+ function _joinPath(path) {
215
+ return typeof path === 'string' ? path : path.filter(v => v).join('/');
158
216
  }
159
217
 
160
218
  // format event name
@@ -5,6 +5,10 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  var _commons = require("@miso.ai/commons");
8
+ const {
9
+ GROUP,
10
+ NAME
11
+ } = _commons.API;
8
12
  const ID = 'std:dry-run';
9
13
  class DryRunPlugin {
10
14
  constructor(options = {}) {
@@ -19,9 +23,11 @@ class DryRunPlugin {
19
23
  // TODO: config({ active })
20
24
 
21
25
  install(_, {
22
- addUrlPass
26
+ addUrlPass,
27
+ addPayloadPass
23
28
  }) {
24
29
  addUrlPass(this._modifyUrl.bind(this));
30
+ addPayloadPass(this._modifyPayload.bind(this));
25
31
  }
26
32
  _modifyUrl({
27
33
  apiGroup,
@@ -30,5 +36,21 @@ class DryRunPlugin {
30
36
  }) {
31
37
  return apiGroup === 'interactions' && apiName === 'upload' ? (0, _commons.addUrlParameter)(url, 'dry_run', '1') : url;
32
38
  }
39
+ _modifyPayload({
40
+ apiGroup,
41
+ apiName,
42
+ payload
43
+ }) {
44
+ if (!payload) {
45
+ return payload; // the GET request
46
+ }
47
+ // questions (ask) and search (hybrid search) only, for now
48
+ if (apiGroup === GROUP.ASK && (apiName === NAME.QUESTIONS || apiName === NAME.SEARCH)) {
49
+ return Object.assign({}, payload, {
50
+ with_request_history: false
51
+ });
52
+ }
53
+ return payload;
54
+ }
33
55
  }
34
56
  exports.default = DryRunPlugin;
package/dist/cjs/lorem.js CHANGED
@@ -8,7 +8,8 @@ var _commons = require("@miso.ai/commons");
8
8
  var _lorem = require("@miso.ai/lorem");
9
9
  var _api = _interopRequireDefault(require("@miso.ai/doggoganger/src/api.js"));
10
10
  var _fetch = _interopRequireDefault(require("@miso.ai/doggoganger/src/fetch.js"));
11
- const _excluded = ["seed"];
11
+ var _utils = require("@miso.ai/doggoganger/src/utils.js");
12
+ const _excluded = ["seed", "latency"];
12
13
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
14
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
14
15
  const PLUGIN_ID = 'std:lorem';
@@ -20,14 +21,22 @@ class LoremPlugin {
20
21
  this._lorem = (0, _lorem.lorem)();
21
22
  this._api = (0, _api.default)();
22
23
  }
24
+
25
+ /**
26
+ * `latency` adds a mock request latency to every api call, in the manner
27
+ * of the doggoganger server's latency middleware: a number of milliseconds
28
+ * (e.g. 500), or `{ min, max }` for a randomized roll.
29
+ */
23
30
  config(_ref = {}) {
24
31
  let {
25
- seed
32
+ seed,
33
+ latency
26
34
  } = _ref,
27
35
  options = _objectWithoutPropertiesLoose(_ref, _excluded);
28
36
  this._lorem = (0, _lorem.lorem)({
29
37
  seed
30
38
  });
39
+ this._latency = latency;
31
40
  this._api = (0, _api.default)(options);
32
41
  }
33
42
  get api() {
@@ -56,8 +65,14 @@ class LoremPlugin {
56
65
  }));
57
66
  };
58
67
  }
59
- _fetch(url, options) {
68
+ async _fetch(url, options) {
69
+ // the seed is captured before the delay, so the generated content stays
70
+ // tied to the request order, not the completion order
60
71
  const seed = this._lorem.prng.seed();
72
+ const latency = this._latency;
73
+ if (latency) {
74
+ await (0, _utils.delay)(typeof latency === 'number' ? latency : (0, _utils.rollLatency)(latency.min || 0, latency.max || 0));
75
+ }
61
76
  return (0, _fetch.default)(this._api, url, Object.assign({
62
77
  seed
63
78
  }, options));
package/package.json CHANGED
@@ -12,8 +12,8 @@
12
12
  "access": "public"
13
13
  },
14
14
  "scripts": {
15
- "build:clean": "npx rimraf dist",
16
- "build:cjs": "BABEL_ENV=cjs npx babel src --root-mode upward --out-dir dist/cjs",
15
+ "build:clean": "rimraf dist",
16
+ "build:cjs": "BABEL_ENV=cjs babel src --root-mode upward --out-dir dist/cjs",
17
17
  "build": "npm run build:clean && npm run build:cjs"
18
18
  },
19
19
  "repository": {
@@ -30,9 +30,9 @@
30
30
  "url": "https://github.com/MisoAI/miso-client-js-sdk/issues"
31
31
  },
32
32
  "dependencies": {
33
- "@miso.ai/commons": "1.13.2-beta.1",
34
- "@miso.ai/doggoganger": "^0.10.0-beta.2",
35
- "@miso.ai/lorem": "^0.10.0-beta.2"
33
+ "@miso.ai/commons": "1.14.0-beta.3",
34
+ "@miso.ai/doggoganger": "^0.10.0-beta.17",
35
+ "@miso.ai/lorem": "^0.10.0-beta.17"
36
36
  },
37
- "version": "1.13.2-beta.1"
37
+ "version": "1.14.0-beta.3"
38
38
  }
package/src/debug.js CHANGED
@@ -2,6 +2,12 @@ import { Logs } from './logs.js';
2
2
 
3
3
  const ID = 'std:debug';
4
4
 
5
+ // the item subworkflow contexts emit per item (one workflow per thread of
6
+ // the list, per message of the conversation), which floods the console.
7
+ // Muted paths stay out of the console only: they are still preserved for
8
+ // the log dump. Configurable via the `mute` option (`mute: []` shows all)
9
+ const DEFAULT_MUTE = Object.freeze(['workflow/thread-items', 'workflow/message-items']);
10
+
5
11
  export default class DebugPlugin {
6
12
 
7
13
  constructor(options = {}) {
@@ -55,6 +61,10 @@ export default class DebugPlugin {
55
61
  this._handleApiEvent(name, { ...data, groupName: path[2] });
56
62
  return;
57
63
  }
64
+ if (path.length === 1 && (name === 'workflow' || name === 'postworkflow')) {
65
+ this._handleClientWorkflowEvent(name, data);
66
+ return;
67
+ }
58
68
  break;
59
69
  case 'plugins':
60
70
  if (path.length === 1) {
@@ -77,7 +87,9 @@ export default class DebugPlugin {
77
87
 
78
88
  bulk && args.push(`(bulk ${bulk.bulkId})`);
79
89
 
80
- args.push(`POST ${pathname}`);
90
+ // the api helpers' fetch defaults to POST when no method is specified
91
+ const { method = 'POST' } = data.options || {};
92
+ args.push(`${method} ${pathname}`);
81
93
 
82
94
  if (groupName === 'interactions') {
83
95
  // TODO: handle multiple interactions
@@ -101,8 +113,16 @@ export default class DebugPlugin {
101
113
  this._log('plugins', eventName, `${plugin.id || '(anonymous)'}`, [plugin, ...data]);
102
114
  }
103
115
 
116
+ // a workflow's creation events on the client follow its context: the
117
+ // workflows of a muted context (the item subworkflows) are muted as well
118
+ _handleClientWorkflowEvent(name, workflow) {
119
+ const context = workflow && workflow._context;
120
+ const silent = !!context && this._isMuted(_joinPath(_pluginComponentPath(context.meta.path)));
121
+ this._logw('client', name, workflow, { silent });
122
+ }
123
+
104
124
  _handlePluginSpecificEvent(pluginId, path, name, data) {
105
- this._logw([pluginId, path.join('.')], name, data);
125
+ this._logw(_pluginComponentPath([pluginId, ...path]), name, data);
106
126
  }
107
127
 
108
128
  _getPath(component) {
@@ -113,28 +133,46 @@ export default class DebugPlugin {
113
133
  return path.reverse();
114
134
  }
115
135
 
116
- _logw(path, name, data) {
136
+ _logw(path, name, data, options) {
117
137
  if (data === undefined) {
118
- this._log(path, name);
138
+ data = [];
119
139
  } else if (Array.isArray(data)) {
120
- this._log(path, name, ...data.map(_wrapObj));
140
+ data = data.map(_wrapObj);
121
141
  } else {
122
- this._log(path, name, _wrapObj(data));
142
+ data = [_wrapObj(data)];
123
143
  }
144
+ this._logp(path, name, data, options);
124
145
  }
125
146
 
126
147
  _log(path, name, ...data) {
127
- this._logr(_path(path), _name(name), ...data);
148
+ this._logp(path, name, data);
149
+ }
150
+
151
+ _logp(path, name, data, { silent = false } = {}) {
152
+ path = _joinPath(path);
153
+ this._write([_path(path), _name(name), ...data], { silent: silent || this._isMuted(path) });
128
154
  }
129
155
 
130
156
  _logr(...data) {
157
+ this._write(data);
158
+ }
159
+
160
+ _write(data, { silent = false } = {}) {
131
161
  const options = this._options.console || {};
132
162
  if (this._options.preserveLog) {
133
163
  this._logs._logs.push(data);
134
164
  }
165
+ if (silent) {
166
+ return;
167
+ }
135
168
  console.log(_tag(options), _style(options), ...data);
136
169
  }
137
170
 
171
+ _isMuted(path) {
172
+ const { mute = DEFAULT_MUTE } = this._options;
173
+ return mute.includes(path);
174
+ }
175
+
138
176
  }
139
177
 
140
178
  function _tag({ text = 'Miso' } = {}) {
@@ -147,7 +185,18 @@ function _style({ color = '#fff', background = '#334cbb' } = {}) {
147
185
 
148
186
  // format path
149
187
  function _path(path) {
150
- return `<${typeof path === 'string' ? path : path.filter(v => v).join('/')}>`;
188
+ return `<${path}>`;
189
+ }
190
+
191
+ // the log path of a component under a plugin, off its meta path — which
192
+ // starts at the plugin ([pluginId, ...rest]): the plugins root reaches the
193
+ // plugins as subtrees, not as parents
194
+ function _pluginComponentPath(path) {
195
+ return [path[0], path.slice(1).join('.')];
196
+ }
197
+
198
+ function _joinPath(path) {
199
+ return typeof path === 'string' ? path : path.filter(v => v).join('/');
151
200
  }
152
201
 
153
202
  // format event name
package/src/dry-run.js CHANGED
@@ -1,4 +1,6 @@
1
- import { addUrlParameter } from '@miso.ai/commons';
1
+ import { API, addUrlParameter } from '@miso.ai/commons';
2
+
3
+ const { GROUP, NAME } = API;
2
4
 
3
5
  const ID = 'std:dry-run';
4
6
 
@@ -16,12 +18,24 @@ export default class DryRunPlugin {
16
18
 
17
19
  // TODO: config({ active })
18
20
 
19
- install(_, { addUrlPass }) {
21
+ install(_, { addUrlPass, addPayloadPass }) {
20
22
  addUrlPass(this._modifyUrl.bind(this));
23
+ addPayloadPass(this._modifyPayload.bind(this));
21
24
  }
22
25
 
23
26
  _modifyUrl({ apiGroup, apiName, url }) {
24
27
  return apiGroup === 'interactions' && apiName === 'upload' ? addUrlParameter(url, 'dry_run', '1') : url;
25
28
  }
26
29
 
30
+ _modifyPayload({ apiGroup, apiName, payload }) {
31
+ if (!payload) {
32
+ return payload; // the GET request
33
+ }
34
+ // questions (ask) and search (hybrid search) only, for now
35
+ if (apiGroup === GROUP.ASK && (apiName === NAME.QUESTIONS || apiName === NAME.SEARCH)) {
36
+ return { ...payload, with_request_history: false };
37
+ }
38
+ return payload;
39
+ }
40
+
27
41
  }
package/src/lorem.js CHANGED
@@ -2,6 +2,7 @@ import { isInBrowser } from '@miso.ai/commons';
2
2
  import { lorem } from '@miso.ai/lorem';
3
3
  import buildApi from '@miso.ai/doggoganger/src/api.js';
4
4
  import fetch from '@miso.ai/doggoganger/src/fetch.js';
5
+ import { delay, rollLatency } from '@miso.ai/doggoganger/src/utils.js';
5
6
 
6
7
  const PLUGIN_ID = 'std:lorem';
7
8
 
@@ -16,8 +17,14 @@ export default class LoremPlugin {
16
17
  this._api = buildApi();
17
18
  }
18
19
 
19
- config({ seed, ...options } = {}) {
20
+ /**
21
+ * `latency` adds a mock request latency to every api call, in the manner
22
+ * of the doggoganger server's latency middleware: a number of milliseconds
23
+ * (e.g. 500), or `{ min, max }` for a randomized roll.
24
+ */
25
+ config({ seed, latency, ...options } = {}) {
20
26
  this._lorem = lorem({ seed });
27
+ this._latency = latency;
21
28
  this._api = buildApi(options);
22
29
  }
23
30
 
@@ -45,8 +52,14 @@ export default class LoremPlugin {
45
52
  };
46
53
  }
47
54
 
48
- _fetch(url, options) {
55
+ async _fetch(url, options) {
56
+ // the seed is captured before the delay, so the generated content stays
57
+ // tied to the request order, not the completion order
49
58
  const seed = this._lorem.prng.seed();
59
+ const latency = this._latency;
60
+ if (latency) {
61
+ await delay(typeof latency === 'number' ? latency : rollLatency(latency.min || 0, latency.max || 0));
62
+ }
50
63
  return fetch(this._api, url, { seed, ...options });
51
64
  }
52
65