@miso.ai/client-sdk-core 1.13.2-beta.1 → 1.14.0-beta.0

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.
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = void 0;
7
7
  var _commons = require("@miso.ai/commons");
8
8
  var _base = _interopRequireDefault(require("./base.js"));
9
+ var _history = _interopRequireDefault(require("./history.0.js"));
9
10
  var _iterable = require("./iterable.js");
10
11
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
12
  const {
@@ -15,6 +16,9 @@ const {
15
16
  class Ask extends _base.default {
16
17
  constructor(api) {
17
18
  super(api, GROUP.ASK);
19
+ // the deployed (v0) user history API; switch back to UserHistory
20
+ // (history.js) when the resource-style API ships
21
+ this.userHistory = new _history.default(api);
18
22
  }
19
23
  async questions(payload, options = {}) {
20
24
  if (isId(payload)) {
@@ -36,6 +40,18 @@ class Ask extends _base.default {
36
40
  method: 'GET'
37
41
  }));
38
42
  }
43
+
44
+ /**
45
+ * Retrieve multiple question-answer pairs at once.
46
+ */
47
+ async answers(payload, options = {}) {
48
+ if (Array.isArray(payload)) {
49
+ payload = {
50
+ question_ids: payload
51
+ };
52
+ }
53
+ return this._run(NAME.ANSWERS, payload, options);
54
+ }
39
55
  async relatedQuestions(payload, options = {}) {
40
56
  return this._run(NAME.RELATED_QUESTIONS, payload, options);
41
57
  }
@@ -8,8 +8,6 @@ var _commons = require("@miso.ai/commons");
8
8
  const _excluded = ["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
  class ApiBase extends _commons.Component {
11
- // TODO: use private fields (may encounter issues with rollup)
12
-
13
11
  constructor(api, apiPath) {
14
12
  super(apiPath, api);
15
13
  this._apiPath = apiPath;
@@ -0,0 +1,212 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _history = _interopRequireDefault(require("./history.js"));
8
+ const _excluded = ["thread_ids"],
9
+ _excluded2 = ["threads"],
10
+ _excluded3 = ["id", "question_id", "time"],
11
+ _excluded4 = ["question_ids"];
12
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
+ 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
+ * The user history API as deployed today (version 0): a flat, POST-only
16
+ * surface where a thread is addressed by the `question_id` of its root
17
+ * question, with its own request/response shapes.
18
+ * @see https://miso-docs.apidocumentation.com/api/genai/user-history
19
+ *
20
+ * It adapts the v0 wire format behind the interface of UserHistory in
21
+ * history.js — the resource-style API the SDK is written against, not
22
+ * released yet. All calls funnel through `_run`, where the resource-style
23
+ * (name, payload, method) is translated to its v0 form and the response
24
+ * value back to the resource-style shape, so the workflow layer stays
25
+ * version-agnostic. When the resource-style API ships, switching the SDK
26
+ * over means using UserHistory in ask.js again.
27
+ */
28
+ class UserHistoryV0 extends _history.default {
29
+ async _run(apiName, payload, options = {}) {
30
+ const {
31
+ name,
32
+ payload: v0Payload,
33
+ adapt
34
+ } = translate(apiName, payload, options);
35
+ const value = await super._run(name, v0Payload, Object.assign({}, options, {
36
+ method: 'POST'
37
+ }));
38
+ return adapt ? adapt(value) : value;
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Translate a resource-style (name, payload, method) call to its v0 form.
44
+ * The v0 payload is always an object — even when the resource-style call
45
+ * carries none (a GET) — so the context plugin's payload pass attaches the
46
+ * user info (user_id/anonymous_id) that v0 endpoints require.
47
+ */
48
+ exports.default = UserHistoryV0;
49
+ function translate(apiName, payload, {
50
+ method = 'POST'
51
+ } = {}) {
52
+ switch (apiName) {
53
+ case 'threads':
54
+ // GET threads -> POST list
55
+ return {
56
+ name: 'list',
57
+ payload: Object.assign({}, payload),
58
+ adapt: adaptThreadList
59
+ };
60
+ case 'threads/_delete':
61
+ {
62
+ const _ref = payload || {},
63
+ {
64
+ thread_ids: question_ids = []
65
+ } = _ref,
66
+ rest = _objectWithoutPropertiesLoose(_ref, _excluded);
67
+ return {
68
+ name: 'delete',
69
+ payload: Object.assign({}, rest, {
70
+ question_ids
71
+ })
72
+ };
73
+ }
74
+ case 'threads/_delete_all':
75
+ return {
76
+ name: 'delete_all',
77
+ payload: Object.assign({}, payload)
78
+ };
79
+ case 'notifications':
80
+ // GET notifications -> POST thread/updates
81
+ return {
82
+ name: 'thread/updates',
83
+ payload: Object.assign({}, payload)
84
+ };
85
+ case 'notifications/dismiss':
86
+ return {
87
+ name: 'thread/updates/dismiss_overall',
88
+ payload: Object.assign({}, payload)
89
+ };
90
+ }
91
+ const segments = apiName.split('/');
92
+ if (segments[0] === 'threads' && segments.length === 2) {
93
+ const thread_id = segments[1]; // the thread id is its root question id
94
+ switch (method) {
95
+ case 'GET':
96
+ // GET threads/{id} -> POST thread
97
+ return {
98
+ name: 'thread',
99
+ payload: Object.assign({}, payload, {
100
+ thread_id
101
+ }),
102
+ adapt: value => adaptThreadDetail(thread_id, value)
103
+ };
104
+ case 'PUT':
105
+ // PUT threads/{id} { title } -> POST thread/rename
106
+ return {
107
+ name: 'thread/rename',
108
+ payload: Object.assign({}, payload, {
109
+ thread_id
110
+ })
111
+ };
112
+ case 'DELETE':
113
+ // DELETE threads/{id} -> POST delete
114
+ return {
115
+ name: 'delete',
116
+ payload: {
117
+ question_ids: [thread_id]
118
+ }
119
+ };
120
+ }
121
+ }
122
+ if (segments[0] === 'threads' && segments.length === 3) {
123
+ const thread_id = segments[1];
124
+ switch (segments[2]) {
125
+ case 'read':
126
+ // POST threads/{id}/read -> POST thread/updates/dismiss_thread
127
+ return {
128
+ name: 'thread/updates/dismiss_thread',
129
+ payload: Object.assign({}, payload, {
130
+ thread_id
131
+ })
132
+ };
133
+ case 'subscribe':
134
+ return {
135
+ name: 'thread/updates/subscribe',
136
+ payload: Object.assign({}, payload, {
137
+ thread_id
138
+ })
139
+ };
140
+ case 'unsubscribe':
141
+ return {
142
+ name: 'thread/updates/unsubscribe',
143
+ payload: Object.assign({}, payload, {
144
+ thread_id
145
+ })
146
+ };
147
+ }
148
+ }
149
+ throw new Error(`Unknown user history API: ${method} ${apiName}`);
150
+ }
151
+
152
+ /**
153
+ * A v0 list response nests the entries under `threads`, alongside the paging
154
+ * fields (has_more, start, rows), which pass through untouched.
155
+ */
156
+ function adaptThreadList(value) {
157
+ if (!value || typeof value !== 'object') {
158
+ return value;
159
+ }
160
+ if (Array.isArray(value)) {
161
+ return value.map(adaptThreadEntry);
162
+ }
163
+ const {
164
+ threads = []
165
+ } = value,
166
+ rest = _objectWithoutPropertiesLoose(value, _excluded2);
167
+ return Object.assign({}, rest, {
168
+ threads: threads.map(adaptThreadEntry)
169
+ });
170
+ }
171
+
172
+ /**
173
+ * A v0 thread entry carries (id, time, question_id, title, subscribed,
174
+ * has_new); the resource-style records read (thread_id, title, updated_at).
175
+ * A thread is keyed by its root question, so question_id serves as the
176
+ * thread id.
177
+ */
178
+ function adaptThreadEntry(entry) {
179
+ if (!entry || typeof entry !== 'object') {
180
+ return entry;
181
+ }
182
+ const {
183
+ id,
184
+ question_id = id,
185
+ time
186
+ } = entry,
187
+ rest = _objectWithoutPropertiesLoose(entry, _excluded3);
188
+ return Object.assign({}, rest, {
189
+ thread_id: question_id,
190
+ question_id,
191
+ updated_at: rest.updated_at !== undefined ? rest.updated_at : time
192
+ });
193
+ }
194
+
195
+ /**
196
+ * The v0 open-thread response carries the question ids (and a has_more flag,
197
+ * passed through) but no thread metadata: synthesize the thread record around
198
+ * them, keyed by the requested thread id.
199
+ */
200
+ function adaptThreadDetail(thread_id, value) {
201
+ if (!value || typeof value !== 'object') {
202
+ return value;
203
+ }
204
+ const {
205
+ question_ids = []
206
+ } = value,
207
+ rest = _objectWithoutPropertiesLoose(value, _excluded4);
208
+ return Object.assign({}, rest, {
209
+ thread_id,
210
+ questions_ids: question_ids
211
+ });
212
+ }
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _commons = require("@miso.ai/commons");
8
+ var _base = _interopRequireDefault(require("./base.js"));
9
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
+ const {
11
+ GROUP
12
+ } = _commons.API;
13
+ class UserHistory extends _base.default {
14
+ constructor(api) {
15
+ super(api, GROUP.ASK_USER_HISTORY);
16
+ }
17
+ async getThreads(options) {
18
+ return this._run('threads', undefined, Object.assign({}, options, {
19
+ method: 'GET'
20
+ }));
21
+ }
22
+ async getThread(threadId, options) {
23
+ return this._run(`threads/${threadId}`, undefined, Object.assign({}, options, {
24
+ method: 'GET'
25
+ }));
26
+ }
27
+ async updateThread(threadId, payload, options) {
28
+ return this._run(`threads/${threadId}`, payload, Object.assign({}, options, {
29
+ method: 'PUT'
30
+ }));
31
+ }
32
+ async deleteThreads(payload, options) {
33
+ return this._run('threads/_delete', payload, options);
34
+ }
35
+ async deleteAllThreads(options) {
36
+ return this._run('threads/_delete_all', undefined, options);
37
+ }
38
+ async deleteThread(threadId, options) {
39
+ return this._run(`threads/${threadId}`, undefined, Object.assign({}, options, {
40
+ method: 'DELETE'
41
+ }));
42
+ }
43
+ async markThreadAsRead(threadId, options) {
44
+ return this._run(`threads/${threadId}/read`, undefined, options);
45
+ }
46
+ async subscribeThread(threadId, options) {
47
+ return this._run(`threads/${threadId}/subscribe`, undefined, options);
48
+ }
49
+ async unsubscribeThread(threadId, options) {
50
+ return this._run(`threads/${threadId}/unsubscribe`, undefined, options);
51
+ }
52
+ async getNotifications(options) {
53
+ return this._run('notifications', undefined, Object.assign({}, options, {
54
+ method: 'GET'
55
+ }));
56
+ }
57
+ async dismissNotifications(options) {
58
+ return this._run('notifications/dismiss', undefined, options);
59
+ }
60
+ }
61
+ exports.default = UserHistory;
@@ -45,11 +45,25 @@ Object.defineProperty(exports, "Search", {
45
45
  return _search.default;
46
46
  }
47
47
  });
48
+ Object.defineProperty(exports, "UserHistory", {
49
+ enumerable: true,
50
+ get: function () {
51
+ return _history.default;
52
+ }
53
+ });
54
+ Object.defineProperty(exports, "UserHistoryV0", {
55
+ enumerable: true,
56
+ get: function () {
57
+ return _history2.default;
58
+ }
59
+ });
48
60
  var _api = _interopRequireDefault(require("./api.js"));
49
61
  var _base = _interopRequireDefault(require("./base.js"));
50
62
  var _helpers = _interopRequireDefault(require("./helpers.js"));
51
63
  var _interactions = _interopRequireDefault(require("./interactions.js"));
52
64
  var _ask = _interopRequireDefault(require("./ask.js"));
65
+ var _history = _interopRequireDefault(require("./history.js"));
66
+ var _history2 = _interopRequireDefault(require("./history.0.js"));
53
67
  var _search = _interopRequireDefault(require("./search.js"));
54
68
  var _recommendation = _interopRequireDefault(require("./recommendation.js"));
55
69
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -41,6 +41,15 @@ class IterableApiStub {
41
41
  options = _objectWithoutPropertiesLoose(_this$_options, _excluded);
42
42
  const stac = new _commons.StallTimeoutAbortController(stallTimeout);
43
43
  signal = _commons.signals.any(this._ac.signal, stac.signal, signal);
44
+ // the stall timer must die with the stream: a timer armed past an abort
45
+ // would keep a Node process alive for the full stall timeout. The signal
46
+ // may have aborted before this iterator was created (it is captured at
47
+ // request time), so the already-aborted case has to be handled as well.
48
+ if (signal.aborted) {
49
+ stac.clear();
50
+ } else {
51
+ signal.addEventListener('abort', () => stac.clear());
52
+ }
44
53
  let prevResponse;
45
54
  const onResponse = (response, finished) => {
46
55
  if (finished) {
@@ -167,7 +167,9 @@ class ClientContext {
167
167
  // helpers //
168
168
  _set(key, value) {
169
169
  this._props[key] = value;
170
- this._plugin._events.emit('set', `${key} = '${value}'`);
170
+ // never emit credentials: the event may end up in the debug console
171
+ const displayed = key === 'auth' && value ? '****' : value;
172
+ this._plugin._events.emit('set', `${key} = '${displayed}'`);
171
173
  }
172
174
  _requireString(key, value) {
173
175
  if (typeof value !== 'string' && typeof value !== 'undefined') {
package/dist/cjs/utils.js CHANGED
@@ -3,6 +3,12 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ Object.defineProperty(exports, "centered", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _commons.centered;
10
+ }
11
+ });
6
12
  Object.defineProperty(exports, "debounce", {
7
13
  enumerable: true,
8
14
  get: function () {
@@ -4,4 +4,4 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _default = exports.default = '1.13.2-beta.1';
7
+ var _default = exports.default = '1.14.0-beta.0';
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,7 +30,7 @@
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"
33
+ "@miso.ai/commons": "1.14.0-beta.0"
34
34
  },
35
- "version": "1.13.2-beta.1"
35
+ "version": "1.14.0-beta.0"
36
36
  }
package/src/api/ask.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { API, defineValues, trimObj } from '@miso.ai/commons';
2
2
  import ApiBase from './base.js';
3
+ import UserHistoryV0 from './history.0.js';
3
4
  import { IdBasedIterableApiStub } from './iterable.js';
4
5
 
5
6
  const { GROUP, NAME } = API;
@@ -8,6 +9,9 @@ export default class Ask extends ApiBase {
8
9
 
9
10
  constructor(api) {
10
11
  super(api, GROUP.ASK);
12
+ // the deployed (v0) user history API; switch back to UserHistory
13
+ // (history.js) when the resource-style API ships
14
+ this.userHistory = new UserHistoryV0(api);
11
15
  }
12
16
 
13
17
  async questions(payload, options = {}) {
@@ -29,6 +33,16 @@ export default class Ask extends ApiBase {
29
33
  return this._run(`${NAME.QUESTIONS}/${questionId}/answer`, undefined, { ...options, method: 'GET' });
30
34
  }
31
35
 
36
+ /**
37
+ * Retrieve multiple question-answer pairs at once.
38
+ */
39
+ async answers(payload, options = {}) {
40
+ if (Array.isArray(payload)) {
41
+ payload = { question_ids: payload };
42
+ }
43
+ return this._run(NAME.ANSWERS, payload, options);
44
+ }
45
+
32
46
  async relatedQuestions(payload, options = {}) {
33
47
  return this._run(NAME.RELATED_QUESTIONS, payload, options);
34
48
  }
package/src/api/base.js CHANGED
@@ -2,8 +2,6 @@ import { Component } from '@miso.ai/commons';
2
2
 
3
3
  export default class ApiBase extends Component {
4
4
 
5
- // TODO: use private fields (may encounter issues with rollup)
6
-
7
5
  constructor(api, apiPath) {
8
6
  super(apiPath, api);
9
7
  this._apiPath = apiPath;
@@ -0,0 +1,119 @@
1
+ import UserHistory from './history.js';
2
+
3
+ /**
4
+ * The user history API as deployed today (version 0): a flat, POST-only
5
+ * surface where a thread is addressed by the `question_id` of its root
6
+ * question, with its own request/response shapes.
7
+ * @see https://miso-docs.apidocumentation.com/api/genai/user-history
8
+ *
9
+ * It adapts the v0 wire format behind the interface of UserHistory in
10
+ * history.js — the resource-style API the SDK is written against, not
11
+ * released yet. All calls funnel through `_run`, where the resource-style
12
+ * (name, payload, method) is translated to its v0 form and the response
13
+ * value back to the resource-style shape, so the workflow layer stays
14
+ * version-agnostic. When the resource-style API ships, switching the SDK
15
+ * over means using UserHistory in ask.js again.
16
+ */
17
+ export default class UserHistoryV0 extends UserHistory {
18
+
19
+ async _run(apiName, payload, options = {}) {
20
+ const { name, payload: v0Payload, adapt } = translate(apiName, payload, options);
21
+ const value = await super._run(name, v0Payload, { ...options, method: 'POST' });
22
+ return adapt ? adapt(value) : value;
23
+ }
24
+
25
+ }
26
+
27
+ /**
28
+ * Translate a resource-style (name, payload, method) call to its v0 form.
29
+ * The v0 payload is always an object — even when the resource-style call
30
+ * carries none (a GET) — so the context plugin's payload pass attaches the
31
+ * user info (user_id/anonymous_id) that v0 endpoints require.
32
+ */
33
+ function translate(apiName, payload, { method = 'POST' } = {}) {
34
+ switch (apiName) {
35
+ case 'threads': // GET threads -> POST list
36
+ return { name: 'list', payload: { ...payload }, adapt: adaptThreadList };
37
+ case 'threads/_delete': {
38
+ const { thread_ids: question_ids = [], ...rest } = payload || {};
39
+ return { name: 'delete', payload: { ...rest, question_ids } };
40
+ }
41
+ case 'threads/_delete_all':
42
+ return { name: 'delete_all', payload: { ...payload } };
43
+ case 'notifications': // GET notifications -> POST thread/updates
44
+ return { name: 'thread/updates', payload: { ...payload } };
45
+ case 'notifications/dismiss':
46
+ return { name: 'thread/updates/dismiss_overall', payload: { ...payload } };
47
+ }
48
+ const segments = apiName.split('/');
49
+ if (segments[0] === 'threads' && segments.length === 2) {
50
+ const thread_id = segments[1]; // the thread id is its root question id
51
+ switch (method) {
52
+ case 'GET': // GET threads/{id} -> POST thread
53
+ return { name: 'thread', payload: { ...payload, thread_id }, adapt: value => adaptThreadDetail(thread_id, value) };
54
+ case 'PUT': // PUT threads/{id} { title } -> POST thread/rename
55
+ return { name: 'thread/rename', payload: { ...payload, thread_id } };
56
+ case 'DELETE': // DELETE threads/{id} -> POST delete
57
+ return { name: 'delete', payload: { question_ids: [thread_id] } };
58
+ }
59
+ }
60
+ if (segments[0] === 'threads' && segments.length === 3) {
61
+ const thread_id = segments[1];
62
+ switch (segments[2]) {
63
+ case 'read': // POST threads/{id}/read -> POST thread/updates/dismiss_thread
64
+ return { name: 'thread/updates/dismiss_thread', payload: { ...payload, thread_id } };
65
+ case 'subscribe':
66
+ return { name: 'thread/updates/subscribe', payload: { ...payload, thread_id } };
67
+ case 'unsubscribe':
68
+ return { name: 'thread/updates/unsubscribe', payload: { ...payload, thread_id } };
69
+ }
70
+ }
71
+ throw new Error(`Unknown user history API: ${method} ${apiName}`);
72
+ }
73
+
74
+ /**
75
+ * A v0 list response nests the entries under `threads`, alongside the paging
76
+ * fields (has_more, start, rows), which pass through untouched.
77
+ */
78
+ function adaptThreadList(value) {
79
+ if (!value || typeof value !== 'object') {
80
+ return value;
81
+ }
82
+ if (Array.isArray(value)) {
83
+ return value.map(adaptThreadEntry);
84
+ }
85
+ const { threads = [], ...rest } = value;
86
+ return { ...rest, threads: threads.map(adaptThreadEntry) };
87
+ }
88
+
89
+ /**
90
+ * A v0 thread entry carries (id, time, question_id, title, subscribed,
91
+ * has_new); the resource-style records read (thread_id, title, updated_at).
92
+ * A thread is keyed by its root question, so question_id serves as the
93
+ * thread id.
94
+ */
95
+ function adaptThreadEntry(entry) {
96
+ if (!entry || typeof entry !== 'object') {
97
+ return entry;
98
+ }
99
+ const { id, question_id = id, time, ...rest } = entry;
100
+ return {
101
+ ...rest,
102
+ thread_id: question_id,
103
+ question_id,
104
+ updated_at: rest.updated_at !== undefined ? rest.updated_at : time,
105
+ };
106
+ }
107
+
108
+ /**
109
+ * The v0 open-thread response carries the question ids (and a has_more flag,
110
+ * passed through) but no thread metadata: synthesize the thread record around
111
+ * them, keyed by the requested thread id.
112
+ */
113
+ function adaptThreadDetail(thread_id, value) {
114
+ if (!value || typeof value !== 'object') {
115
+ return value;
116
+ }
117
+ const { question_ids = [], ...rest } = value;
118
+ return { ...rest, thread_id, questions_ids: question_ids };
119
+ }
@@ -0,0 +1,56 @@
1
+ import { API } from '@miso.ai/commons';
2
+ import ApiBase from './base.js';
3
+
4
+ const { GROUP } = API;
5
+
6
+ export default class UserHistory extends ApiBase {
7
+
8
+ constructor(api) {
9
+ super(api, GROUP.ASK_USER_HISTORY);
10
+ }
11
+
12
+ async getThreads(options) {
13
+ return this._run('threads', undefined, { ...options, method: 'GET' });
14
+ }
15
+
16
+ async getThread(threadId, options) {
17
+ return this._run(`threads/${threadId}`, undefined, { ...options, method: 'GET' });
18
+ }
19
+
20
+ async updateThread(threadId, payload, options) {
21
+ return this._run(`threads/${threadId}`, payload, { ...options, method: 'PUT' });
22
+ }
23
+
24
+ async deleteThreads(payload, options) {
25
+ return this._run('threads/_delete', payload, options);
26
+ }
27
+
28
+ async deleteAllThreads(options) {
29
+ return this._run('threads/_delete_all', undefined, options);
30
+ }
31
+
32
+ async deleteThread(threadId, options) {
33
+ return this._run(`threads/${threadId}`, undefined, { ...options, method: 'DELETE' });
34
+ }
35
+
36
+ async markThreadAsRead(threadId, options) {
37
+ return this._run(`threads/${threadId}/read`, undefined, options);
38
+ }
39
+
40
+ async subscribeThread(threadId, options) {
41
+ return this._run(`threads/${threadId}/subscribe`, undefined, options);
42
+ }
43
+
44
+ async unsubscribeThread(threadId, options) {
45
+ return this._run(`threads/${threadId}/unsubscribe`, undefined, options);
46
+ }
47
+
48
+ async getNotifications(options) {
49
+ return this._run('notifications', undefined, { ...options, method: 'GET' });
50
+ }
51
+
52
+ async dismissNotifications(options) {
53
+ return this._run('notifications/dismiss', undefined, options);
54
+ }
55
+
56
+ }
package/src/api/index.js CHANGED
@@ -3,5 +3,7 @@ export { default as ApiBase } from './base.js';
3
3
  export { default as ApiHelpers } from './helpers.js';
4
4
  export { default as Interactions } from './interactions.js';
5
5
  export { default as Ask } from './ask.js';
6
+ export { default as UserHistory } from './history.js';
7
+ export { default as UserHistoryV0 } from './history.0.js';
6
8
  export { default as Search } from './search.js';
7
9
  export { default as Recommendation } from './recommendation.js';
@@ -33,6 +33,15 @@ export class IterableApiStub {
33
33
  let { pollingInterval: interval, signal, stallTimeout = 120000, ...options } = this._options;
34
34
  const stac = new StallTimeoutAbortController(stallTimeout);
35
35
  signal = signals.any(this._ac.signal, stac.signal, signal);
36
+ // the stall timer must die with the stream: a timer armed past an abort
37
+ // would keep a Node process alive for the full stall timeout. The signal
38
+ // may have aborted before this iterator was created (it is captured at
39
+ // request time), so the already-aborted case has to be handled as well.
40
+ if (signal.aborted) {
41
+ stac.clear();
42
+ } else {
43
+ signal.addEventListener('abort', () => stac.clear());
44
+ }
36
45
 
37
46
  let prevResponse;
38
47
  const onResponse = (response, finished) => {
@@ -140,7 +140,9 @@ class ClientContext {
140
140
  // helpers //
141
141
  _set(key, value) {
142
142
  this._props[key] = value;
143
- this._plugin._events.emit('set', `${key} = '${value}'`);
143
+ // never emit credentials: the event may end up in the debug console
144
+ const displayed = key === 'auth' && value ? '****' : value;
145
+ this._plugin._events.emit('set', `${key} = '${displayed}'`);
144
146
  }
145
147
 
146
148
  _requireString(key, value) {
package/src/utils.js CHANGED
@@ -1 +1 @@
1
- export { viewable, debounce } from '@miso.ai/commons';
1
+ export { viewable, centered, debounce } from '@miso.ai/commons';
package/src/version.js CHANGED
@@ -1 +1 @@
1
- export default '1.13.2-beta.1';
1
+ export default '1.14.0-beta.0';