@miso.ai/client-sdk-core 1.13.0-beta.8 → 1.13.1-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.
- package/dist/cjs/api/ask.js +8 -2
- package/dist/cjs/api/helpers.js +22 -13
- package/dist/cjs/api/iterable.js +14 -11
- package/dist/cjs/client.js +9 -3
- package/dist/cjs/plugin/analytics.js +13 -3
- package/dist/cjs/plugin/context.js +1 -1
- package/dist/cjs/plugin/native-fetch.js +8 -0
- package/dist/cjs/plugin/page-info.js +2 -0
- package/dist/cjs/plugin/plugin-root.js +14 -4
- package/dist/cjs/plugin/urls.js +6 -1
- package/dist/cjs/version.js +1 -1
- package/package.json +2 -2
- package/src/api/ask.js +11 -3
- package/src/api/helpers.js +10 -5
- package/src/api/iterable.js +22 -17
- package/src/client.js +9 -2
- package/src/plugin/analytics.js +14 -0
- package/src/plugin/context.js +2 -2
- package/src/plugin/native-fetch.js +9 -0
- package/src/plugin/page-info.js +2 -0
- package/src/plugin/plugin-root.js +15 -5
- package/src/plugin/urls.js +8 -1
- package/src/version.js +1 -1
package/dist/cjs/api/ask.js
CHANGED
|
@@ -69,7 +69,7 @@ class Ask extends _base.default {
|
|
|
69
69
|
exports.default = Ask;
|
|
70
70
|
class Answer extends _iterable.IdBasedIterableApiStub {
|
|
71
71
|
constructor(api, response, options = {}) {
|
|
72
|
-
super(api, '_questionGet', response.question_id, options);
|
|
72
|
+
super(api, '_questionGet', response.question_id, mergeCustomApiIterator(api, options));
|
|
73
73
|
this._response = response;
|
|
74
74
|
}
|
|
75
75
|
get questionId() {
|
|
@@ -78,7 +78,7 @@ class Answer extends _iterable.IdBasedIterableApiStub {
|
|
|
78
78
|
}
|
|
79
79
|
class SearchResult extends _iterable.IdBasedIterableApiStub {
|
|
80
80
|
constructor(api, response, options = {}) {
|
|
81
|
-
super(api, '_searchGet', response.question_id, options);
|
|
81
|
+
super(api, '_searchGet', response.question_id, mergeCustomApiIterator(api, options));
|
|
82
82
|
(0, _commons.defineValues)(this, response);
|
|
83
83
|
this._response = response;
|
|
84
84
|
}
|
|
@@ -90,4 +90,10 @@ class SearchResult extends _iterable.IdBasedIterableApiStub {
|
|
|
90
90
|
// helpers //
|
|
91
91
|
function isId(value) {
|
|
92
92
|
return typeof value === 'string' && value.charAt(0) !== '{';
|
|
93
|
+
}
|
|
94
|
+
function mergeCustomApiIterator(api, options) {
|
|
95
|
+
const customIterator = api.helpers._root._customApiIterator;
|
|
96
|
+
return (0, _commons.trimObj)(Object.assign({
|
|
97
|
+
customIterator
|
|
98
|
+
}, options));
|
|
93
99
|
}
|
package/dist/cjs/api/helpers.js
CHANGED
|
@@ -6,35 +6,41 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
var _commons = require("@miso.ai/commons");
|
|
8
8
|
var _constants = require("../constants.js");
|
|
9
|
+
const _excluded = ["method", "headers", "timeout"];
|
|
10
|
+
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; }
|
|
9
11
|
class ApiHelpers {
|
|
10
12
|
constructor(client, root) {
|
|
11
13
|
this._client = client;
|
|
12
14
|
this._root = root;
|
|
13
15
|
this._bulk = new _commons.Bulk(this._runBulkFetch.bind(this), client._error.bind(client));
|
|
14
16
|
}
|
|
15
|
-
async fetch(url, payload, {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
async fetch(url, payload, _ref = {}) {
|
|
18
|
+
let {
|
|
19
|
+
method = 'POST',
|
|
20
|
+
headers,
|
|
21
|
+
timeout
|
|
22
|
+
} = _ref,
|
|
23
|
+
options = _objectWithoutPropertiesLoose(_ref, _excluded);
|
|
20
24
|
const {
|
|
21
25
|
apiKey,
|
|
22
26
|
request = {}
|
|
23
27
|
} = this._client.options;
|
|
24
28
|
timeout = timeout || request.timeout;
|
|
25
29
|
|
|
26
|
-
// TODO: external abort signal
|
|
27
30
|
// TODO: organize arguments
|
|
28
31
|
const body = method !== 'GET' && payload != undefined ? JSON.stringify(payload) : undefined;
|
|
32
|
+
|
|
33
|
+
// TODO: merge signal from options if any
|
|
29
34
|
const signal = timeout ? AbortSignal.timeout(timeout) : undefined;
|
|
30
|
-
const res = await (this._root._customFetch ||
|
|
35
|
+
const res = await (this._root._customFetch || fetch)(url, (0, _commons.trimObj)(Object.assign({
|
|
31
36
|
method,
|
|
32
37
|
headers,
|
|
33
|
-
body,
|
|
34
38
|
cache: 'no-cache',
|
|
35
|
-
mode: 'cors'
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
mode: 'cors'
|
|
40
|
+
}, options, {
|
|
41
|
+
signal,
|
|
42
|
+
body
|
|
43
|
+
})));
|
|
38
44
|
const resBody = await res.json();
|
|
39
45
|
if (res.status >= 400 || resBody.errors) {
|
|
40
46
|
var err = new Error(resBody.message);
|
|
@@ -102,7 +108,10 @@ class ApiHelpers {
|
|
|
102
108
|
if (method && method !== 'POST') {
|
|
103
109
|
throw new Error(`Non-POST API is not supported in useBeacon mode: ${url}`);
|
|
104
110
|
}
|
|
105
|
-
|
|
111
|
+
if (!this._root._customSendBeacon && !navigator.sendBeacon) {
|
|
112
|
+
throw new Error(`Send beacon is not supported in this environment.`);
|
|
113
|
+
}
|
|
114
|
+
const successful = this._root._customSendBeacon ? this._root._customSendBeacon(url, JSON.stringify(payload)) : navigator.sendBeacon(url, JSON.stringify(payload));
|
|
106
115
|
if (!successful) {
|
|
107
116
|
throw new Error(`Send beacon unsuccessful: ${url}`);
|
|
108
117
|
}
|
|
@@ -113,7 +122,7 @@ class ApiHelpers {
|
|
|
113
122
|
} = this._client.options;
|
|
114
123
|
const apiName = paths.filter(s => s).join('/');
|
|
115
124
|
const url = `${this.getApiEndpoint(apiName)}/${apiName}`;
|
|
116
|
-
return `${url}?api_key=${
|
|
125
|
+
return `${url}?api_key=${encodeURIComponent(apiKey)}`;
|
|
117
126
|
}
|
|
118
127
|
getApiEndpoint(apiName) {
|
|
119
128
|
const {
|
package/dist/cjs/api/iterable.js
CHANGED
|
@@ -27,8 +27,11 @@ class IterableApiStub {
|
|
|
27
27
|
} = {}) => {
|
|
28
28
|
// TODO: pass signal
|
|
29
29
|
const response = await this.get();
|
|
30
|
-
return [response,
|
|
30
|
+
return [response, isFinished(response), revisionOf(response)];
|
|
31
31
|
};
|
|
32
|
+
if (typeof this._options.customIterator === 'function') {
|
|
33
|
+
return this._options.customIterator.call(this, fetch);
|
|
34
|
+
}
|
|
32
35
|
let _this$_options = this._options,
|
|
33
36
|
{
|
|
34
37
|
pollingInterval: interval,
|
|
@@ -42,7 +45,7 @@ class IterableApiStub {
|
|
|
42
45
|
const onResponse = (response, finished) => {
|
|
43
46
|
if (finished) {
|
|
44
47
|
stac.clear();
|
|
45
|
-
} else if (
|
|
48
|
+
} else if (isUpdated(prevResponse, response)) {
|
|
46
49
|
stac.touch();
|
|
47
50
|
}
|
|
48
51
|
prevResponse = response;
|
|
@@ -53,15 +56,6 @@ class IterableApiStub {
|
|
|
53
56
|
onResponse
|
|
54
57
|
}, options))[Symbol.asyncIterator]();
|
|
55
58
|
}
|
|
56
|
-
_isFinished(response) {
|
|
57
|
-
return !!(response && response.finished);
|
|
58
|
-
}
|
|
59
|
-
_isUpdated(previousResponse, newResponse) {
|
|
60
|
-
return !previousResponse || previousResponse.answer_stage !== newResponse.answer_stage || lengthOf(previousResponse.answer) !== lengthOf(newResponse.answer) || lengthOf(previousResponse.reasoning) !== lengthOf(newResponse.reasoning);
|
|
61
|
-
}
|
|
62
|
-
_revisionOf(response) {
|
|
63
|
-
return response && response.revision;
|
|
64
|
-
}
|
|
65
59
|
}
|
|
66
60
|
exports.IterableApiStub = IterableApiStub;
|
|
67
61
|
class IdBasedIterableApiStub extends IterableApiStub {
|
|
@@ -76,6 +70,15 @@ class IdBasedIterableApiStub extends IterableApiStub {
|
|
|
76
70
|
}
|
|
77
71
|
}
|
|
78
72
|
exports.IdBasedIterableApiStub = IdBasedIterableApiStub;
|
|
73
|
+
function isFinished(response) {
|
|
74
|
+
return !!(response && response.finished);
|
|
75
|
+
}
|
|
76
|
+
function isUpdated(previousResponse, newResponse) {
|
|
77
|
+
return !previousResponse || previousResponse.answer_stage !== newResponse.answer_stage || lengthOf(previousResponse.answer) !== lengthOf(newResponse.answer) || lengthOf(previousResponse.reasoning) !== lengthOf(newResponse.reasoning);
|
|
78
|
+
}
|
|
79
|
+
function revisionOf(response) {
|
|
80
|
+
return response && response.revision;
|
|
81
|
+
}
|
|
79
82
|
function lengthOf(value = '') {
|
|
80
83
|
return value.length;
|
|
81
84
|
}
|
package/dist/cjs/client.js
CHANGED
|
@@ -11,11 +11,13 @@ var _context = _interopRequireDefault(require("./context.js"));
|
|
|
11
11
|
var helpers = _interopRequireWildcard(require("./utils.js"));
|
|
12
12
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
13
13
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
|
-
const
|
|
15
|
-
currentScript
|
|
16
|
-
} = document;
|
|
14
|
+
const currentScript = _commons.isInBrowser ? document.currentScript : undefined;
|
|
17
15
|
class MisoClient extends _commons.Component {
|
|
18
16
|
static attach() {
|
|
17
|
+
if (typeof window === 'undefined') {
|
|
18
|
+
console.warn(`MisoClient cannot be attached in non-browser environment.`);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
19
21
|
(window.MisoClients || (window.MisoClients = [])).push(MisoClient);
|
|
20
22
|
if (window.MisoClient) {
|
|
21
23
|
if (window.MisoClient !== MisoClient) {
|
|
@@ -62,6 +64,10 @@ class MisoClient extends _commons.Component {
|
|
|
62
64
|
delete options.apiHost;
|
|
63
65
|
return (0, _commons.trimObj)(options);
|
|
64
66
|
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Used by shopify plugin.
|
|
70
|
+
*/
|
|
65
71
|
_readConfigFromScriptUrl() {
|
|
66
72
|
const url = currentScript.src || currentScript.href; // might be <link> as well
|
|
67
73
|
const params = new URL(new Request(url).url).searchParams;
|
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
var _commons = require("@miso.ai/commons");
|
|
8
|
-
function _objectDestructuringEmpty(t) { if (null == t) throw new TypeError("Cannot destructure " + t); }
|
|
8
|
+
function _objectDestructuringEmpty(t) { if (null == t) throw new TypeError("Cannot destructure " + t); } // [browser only]
|
|
9
9
|
const PLUGIN_ID = 'std:analytics';
|
|
10
10
|
class AnalyticsPlugin extends _commons.Component {
|
|
11
11
|
static get id() {
|
|
@@ -136,6 +136,12 @@ class Analytics {
|
|
|
136
136
|
this._loadingAt = undefined;
|
|
137
137
|
this._readyAt = undefined;
|
|
138
138
|
this.config();
|
|
139
|
+
this._engagedSeconds = 0;
|
|
140
|
+
this._engagementInterval = setInterval(() => {
|
|
141
|
+
if (this._plugin._engagement.engaged && this._readyAt) {
|
|
142
|
+
this._engagedSeconds += 1;
|
|
143
|
+
}
|
|
144
|
+
}, 1000);
|
|
139
145
|
}
|
|
140
146
|
_injectWorkflow(workflow) {
|
|
141
147
|
this._listenToLiftcycleEvents(workflow);
|
|
@@ -163,6 +169,7 @@ class Analytics {
|
|
|
163
169
|
this._startAt = Date.now();
|
|
164
170
|
this._loadingAt = undefined;
|
|
165
171
|
this._readyAt = undefined;
|
|
172
|
+
this._engagedSeconds = 0;
|
|
166
173
|
}
|
|
167
174
|
_handleLoading({
|
|
168
175
|
session
|
|
@@ -190,7 +197,8 @@ class Analytics {
|
|
|
190
197
|
analytics_timestamp: state.timestamp,
|
|
191
198
|
user_engagement_time: state.userEngagementTime,
|
|
192
199
|
user_idle_time: state.userIdleTime,
|
|
193
|
-
user_waiting_time: state.userWaitingTime
|
|
200
|
+
user_waiting_time: state.userWaitingTime,
|
|
201
|
+
user_engagement_time_v2: state.userEngagementTimeV2
|
|
194
202
|
}
|
|
195
203
|
}
|
|
196
204
|
});
|
|
@@ -208,6 +216,7 @@ class Analytics {
|
|
|
208
216
|
let userEngagementTime = 0,
|
|
209
217
|
userIdleTime = 0,
|
|
210
218
|
userWaitingTime = 0;
|
|
219
|
+
let userEngagementTimeV2 = this._engagedSeconds * 1000;
|
|
211
220
|
if (loadingAt !== undefined) {
|
|
212
221
|
userWaitingTime = currentTime - loadingAt;
|
|
213
222
|
}
|
|
@@ -220,7 +229,8 @@ class Analytics {
|
|
|
220
229
|
timestamp: currentTime,
|
|
221
230
|
userWaitingTime,
|
|
222
231
|
userEngagementTime,
|
|
223
|
-
userIdleTime
|
|
232
|
+
userIdleTime,
|
|
233
|
+
userEngagementTimeV2
|
|
224
234
|
});
|
|
225
235
|
}
|
|
226
236
|
_syncEngagementState() {
|
|
@@ -114,7 +114,7 @@ function getAutoAnonymousId() {
|
|
|
114
114
|
// 1. Cache the value for the page
|
|
115
115
|
// 2. Get and set the value from cookies/localStorage is possible
|
|
116
116
|
// 3. In case cookies/localStorage are disabled, generate a new value for each page
|
|
117
|
-
return _pageBasedAutoAnonymousId || (_pageBasedAutoAnonymousId = (0, _commons.getOrComputeFromStorage)('miso_anonymous_id', _commons.uuidv4));
|
|
117
|
+
return _pageBasedAutoAnonymousId || (_pageBasedAutoAnonymousId = _commons.isInBrowser ? (0, _commons.getOrComputeFromStorage)('miso_anonymous_id', _commons.uuidv4) : (0, _commons.uuidv4)());
|
|
118
118
|
}
|
|
119
119
|
class ClientContext {
|
|
120
120
|
constructor(plugin) {
|
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
+
var _commons = require("@miso.ai/commons");
|
|
7
8
|
const PLUGIN_ID = 'std:native-fetch';
|
|
8
9
|
function isNativeFunction(fn) {
|
|
9
10
|
return fn.toString().indexOf("[native code]") > -1;
|
|
@@ -11,6 +12,9 @@ function isNativeFunction(fn) {
|
|
|
11
12
|
let _fetchSource;
|
|
12
13
|
let _fetchError;
|
|
13
14
|
const fetchFn = (() => {
|
|
15
|
+
if (!_commons.isInBrowser) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
14
18
|
if (isNativeFunction(window.fetch)) {
|
|
15
19
|
_fetchSource = 'original';
|
|
16
20
|
return window.fetch;
|
|
@@ -32,6 +36,10 @@ class NativeFetchPlugin {
|
|
|
32
36
|
return PLUGIN_ID;
|
|
33
37
|
}
|
|
34
38
|
install(MisoClient, context) {
|
|
39
|
+
if (!_commons.isInBrowser) {
|
|
40
|
+
MisoClient.debug(`<plugin:${PLUGIN_ID}>`, '[info]', `Not in browser, skipped`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
35
43
|
if (!fetchFn) {
|
|
36
44
|
MisoClient.debug(`<plugin:${PLUGIN_ID}>`, '[error]', `Failed to obtain native fetch: ${_fetchError.message}`);
|
|
37
45
|
return;
|
|
@@ -16,7 +16,6 @@ class PluginRoot extends _commons.Registry {
|
|
|
16
16
|
keyName: 'id'
|
|
17
17
|
});
|
|
18
18
|
this._root = root;
|
|
19
|
-
this._currentScript = document.currentScript;
|
|
20
19
|
this._events._replays.add('install').add('subtree');
|
|
21
20
|
this._installed = {};
|
|
22
21
|
this._installedResolutions = {};
|
|
@@ -116,6 +115,12 @@ class PluginRoot extends _commons.Registry {
|
|
|
116
115
|
}
|
|
117
116
|
this._root._customSendBeacon = sendBeacon;
|
|
118
117
|
}
|
|
118
|
+
setCustomApiIterator(customApiIterator) {
|
|
119
|
+
if (typeof customApiIterator !== 'function') {
|
|
120
|
+
throw new Error(`Expect parameter to be a function: ${customApiIterator}`);
|
|
121
|
+
}
|
|
122
|
+
this._root._customApiIterator = customApiIterator;
|
|
123
|
+
}
|
|
119
124
|
onHubUpdate(callback) {
|
|
120
125
|
if (typeof callback !== 'function') {
|
|
121
126
|
throw new Error(`Expect parameter to be a function: ${callback}`);
|
|
@@ -199,7 +204,7 @@ class PluginRoot extends _commons.Registry {
|
|
|
199
204
|
}
|
|
200
205
|
}
|
|
201
206
|
async _tryRegisterRemotely(id) {
|
|
202
|
-
if (id.startsWith('std:')) {
|
|
207
|
+
if (id.startsWith('std:') && _commons.isInBrowser) {
|
|
203
208
|
try {
|
|
204
209
|
await this._registerStdRemotely(id);
|
|
205
210
|
return;
|
|
@@ -210,6 +215,11 @@ class PluginRoot extends _commons.Registry {
|
|
|
210
215
|
// TODO: try as URL
|
|
211
216
|
throw new Error(`Cannot register plugin remotely: ${id}`);
|
|
212
217
|
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* [browser only]
|
|
221
|
+
* @param {string} id
|
|
222
|
+
*/
|
|
213
223
|
async _registerStdRemotely(id) {
|
|
214
224
|
const {
|
|
215
225
|
version
|
|
@@ -221,7 +231,7 @@ class PluginRoot extends _commons.Registry {
|
|
|
221
231
|
// skip if already exists
|
|
222
232
|
const script = document.createElement('script');
|
|
223
233
|
script.async = true;
|
|
224
|
-
script.src = (0, _urls.getPluginScriptUrl)(id, version
|
|
234
|
+
script.src = (0, _urls.getPluginScriptUrl)(id, version);
|
|
225
235
|
script.setAttribute('data-request', request);
|
|
226
236
|
document.head.appendChild(script);
|
|
227
237
|
// TODO: hook up error event
|
|
@@ -239,7 +249,7 @@ class PluginRoot extends _commons.Registry {
|
|
|
239
249
|
exports.default = PluginRoot;
|
|
240
250
|
class PluginContext {
|
|
241
251
|
constructor(root, classes) {
|
|
242
|
-
(0, _commons.delegateGetters)(this, root, ['getPluginClass', 'addSubtree', 'addPayloadPass', 'addHeadersPass', 'addUrlPass', 'setCustomFetch', 'setCustomSendBeacon', 'onHubUpdate', 'onHubEmit', 'whenInstalled', 'whenRegistered']);
|
|
252
|
+
(0, _commons.delegateGetters)(this, root, ['getPluginClass', 'addSubtree', 'addPayloadPass', 'addHeadersPass', 'addUrlPass', 'setCustomFetch', 'setCustomSendBeacon', 'setCustomApiIterator', 'onHubUpdate', 'onHubEmit', 'whenInstalled', 'whenRegistered']);
|
|
243
253
|
(0, _commons.defineValues)(this, {
|
|
244
254
|
classes
|
|
245
255
|
});
|
package/dist/cjs/plugin/urls.js
CHANGED
|
@@ -4,10 +4,15 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.getPluginScriptUrl = getPluginScriptUrl;
|
|
7
|
-
|
|
7
|
+
var _commons = require("@miso.ai/commons");
|
|
8
|
+
const currentScript = _commons.isInBrowser ? document.currentScript : undefined;
|
|
9
|
+
function getPluginScriptUrl(id, version) {
|
|
8
10
|
// TODO: look up by manifest
|
|
9
11
|
const pkgName = id.slice(4);
|
|
10
12
|
if (version === 'dev') {
|
|
13
|
+
if (!currentScript) {
|
|
14
|
+
throw new Error(`Cannot get plugin script URL for ${id}: no currentScript.`);
|
|
15
|
+
}
|
|
11
16
|
const src = currentScript.src;
|
|
12
17
|
const searchIndex = src.indexOf('?');
|
|
13
18
|
const k = searchIndex < 0 ? src.length : searchIndex;
|
package/dist/cjs/version.js
CHANGED
package/package.json
CHANGED
package/src/api/ask.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { API, defineValues } from '@miso.ai/commons';
|
|
1
|
+
import { API, defineValues, trimObj } from '@miso.ai/commons';
|
|
2
2
|
import ApiBase from './base.js';
|
|
3
3
|
import { IdBasedIterableApiStub } from './iterable.js';
|
|
4
4
|
|
|
@@ -65,7 +65,7 @@ export default class Ask extends ApiBase {
|
|
|
65
65
|
class Answer extends IdBasedIterableApiStub {
|
|
66
66
|
|
|
67
67
|
constructor(api, response, options = {}) {
|
|
68
|
-
super(api, '_questionGet', response.question_id, options);
|
|
68
|
+
super(api, '_questionGet', response.question_id, mergeCustomApiIterator(api, options));
|
|
69
69
|
this._response = response;
|
|
70
70
|
}
|
|
71
71
|
|
|
@@ -78,7 +78,7 @@ class Answer extends IdBasedIterableApiStub {
|
|
|
78
78
|
class SearchResult extends IdBasedIterableApiStub {
|
|
79
79
|
|
|
80
80
|
constructor(api, response, options = {}) {
|
|
81
|
-
super(api, '_searchGet', response.question_id, options);
|
|
81
|
+
super(api, '_searchGet', response.question_id, mergeCustomApiIterator(api, options));
|
|
82
82
|
defineValues(this, response);
|
|
83
83
|
this._response = response;
|
|
84
84
|
}
|
|
@@ -93,3 +93,11 @@ class SearchResult extends IdBasedIterableApiStub {
|
|
|
93
93
|
function isId(value) {
|
|
94
94
|
return typeof value === 'string' && value.charAt(0) !== '{';
|
|
95
95
|
}
|
|
96
|
+
|
|
97
|
+
function mergeCustomApiIterator(api, options) {
|
|
98
|
+
const customIterator = api.helpers._root._customApiIterator;
|
|
99
|
+
return trimObj({
|
|
100
|
+
customIterator,
|
|
101
|
+
...options,
|
|
102
|
+
});
|
|
103
|
+
}
|
package/src/api/helpers.js
CHANGED
|
@@ -13,23 +13,25 @@ export default class ApiHelpers {
|
|
|
13
13
|
method = 'POST',
|
|
14
14
|
headers,
|
|
15
15
|
timeout,
|
|
16
|
+
...options
|
|
16
17
|
} = {}) {
|
|
17
18
|
const { apiKey, request = {} } = this._client.options;
|
|
18
19
|
timeout = timeout || request.timeout;
|
|
19
20
|
|
|
20
|
-
// TODO: external abort signal
|
|
21
21
|
// TODO: organize arguments
|
|
22
22
|
const body = method !== 'GET' && payload != undefined ? JSON.stringify(payload) : undefined;
|
|
23
23
|
|
|
24
|
+
// TODO: merge signal from options if any
|
|
24
25
|
const signal = timeout ? AbortSignal.timeout(timeout) : undefined;
|
|
25
26
|
|
|
26
|
-
const res = await (this._root._customFetch ||
|
|
27
|
+
const res = await (this._root._customFetch || fetch)(url, trimObj({
|
|
27
28
|
method,
|
|
28
29
|
headers,
|
|
29
|
-
body,
|
|
30
30
|
cache: 'no-cache',
|
|
31
31
|
mode: 'cors',
|
|
32
|
+
...options,
|
|
32
33
|
signal,
|
|
34
|
+
body,
|
|
33
35
|
}));
|
|
34
36
|
|
|
35
37
|
const resBody = await res.json();
|
|
@@ -78,9 +80,12 @@ export default class ApiHelpers {
|
|
|
78
80
|
if (method && method !== 'POST') {
|
|
79
81
|
throw new Error(`Non-POST API is not supported in useBeacon mode: ${url}`);
|
|
80
82
|
}
|
|
83
|
+
if (!this._root._customSendBeacon && !navigator.sendBeacon) {
|
|
84
|
+
throw new Error(`Send beacon is not supported in this environment.`);
|
|
85
|
+
}
|
|
81
86
|
const successful = this._root._customSendBeacon ?
|
|
82
87
|
this._root._customSendBeacon(url, JSON.stringify(payload)) :
|
|
83
|
-
|
|
88
|
+
navigator.sendBeacon(url, JSON.stringify(payload));
|
|
84
89
|
if (!successful) {
|
|
85
90
|
throw new Error(`Send beacon unsuccessful: ${url}`);
|
|
86
91
|
}
|
|
@@ -90,7 +95,7 @@ export default class ApiHelpers {
|
|
|
90
95
|
const { apiKey } = this._client.options;
|
|
91
96
|
const apiName = paths.filter(s => s).join('/');
|
|
92
97
|
const url = `${this.getApiEndpoint(apiName)}/${apiName}`;
|
|
93
|
-
return `${url}?api_key=${
|
|
98
|
+
return `${url}?api_key=${encodeURIComponent(apiKey)}`;
|
|
94
99
|
}
|
|
95
100
|
|
|
96
101
|
getApiEndpoint(apiName) {
|
package/src/api/iterable.js
CHANGED
|
@@ -23,8 +23,13 @@ export class IterableApiStub {
|
|
|
23
23
|
const fetch = async ({ signal } = {}) => {
|
|
24
24
|
// TODO: pass signal
|
|
25
25
|
const response = await this.get();
|
|
26
|
-
return [response,
|
|
26
|
+
return [response, isFinished(response), revisionOf(response)];
|
|
27
27
|
};
|
|
28
|
+
|
|
29
|
+
if (typeof this._options.customIterator === 'function') {
|
|
30
|
+
return this._options.customIterator.call(this, fetch);
|
|
31
|
+
}
|
|
32
|
+
|
|
28
33
|
let { pollingInterval: interval, signal, stallTimeout = 120000, ...options } = this._options;
|
|
29
34
|
const stac = new StallTimeoutAbortController(stallTimeout);
|
|
30
35
|
signal = signals.any(this._ac.signal, stac.signal, signal);
|
|
@@ -33,7 +38,7 @@ export class IterableApiStub {
|
|
|
33
38
|
const onResponse = (response, finished) => {
|
|
34
39
|
if (finished) {
|
|
35
40
|
stac.clear();
|
|
36
|
-
} else if (
|
|
41
|
+
} else if (isUpdated(prevResponse, response)) {
|
|
37
42
|
stac.touch();
|
|
38
43
|
}
|
|
39
44
|
prevResponse = response;
|
|
@@ -41,21 +46,6 @@ export class IterableApiStub {
|
|
|
41
46
|
return polling(fetch, { interval, signal, onResponse, ...options })[Symbol.asyncIterator]();
|
|
42
47
|
}
|
|
43
48
|
|
|
44
|
-
_isFinished(response) {
|
|
45
|
-
return !!(response && response.finished);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
_isUpdated(previousResponse, newResponse) {
|
|
49
|
-
return !previousResponse ||
|
|
50
|
-
previousResponse.answer_stage !== newResponse.answer_stage ||
|
|
51
|
-
lengthOf(previousResponse.answer) !== lengthOf(newResponse.answer) ||
|
|
52
|
-
lengthOf(previousResponse.reasoning) !== lengthOf(newResponse.reasoning);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
_revisionOf(response) {
|
|
56
|
-
return response && response.revision;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
49
|
}
|
|
60
50
|
|
|
61
51
|
export class IdBasedIterableApiStub extends IterableApiStub {
|
|
@@ -73,6 +63,21 @@ export class IdBasedIterableApiStub extends IterableApiStub {
|
|
|
73
63
|
|
|
74
64
|
}
|
|
75
65
|
|
|
66
|
+
function isFinished(response) {
|
|
67
|
+
return !!(response && response.finished);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function isUpdated(previousResponse, newResponse) {
|
|
71
|
+
return !previousResponse ||
|
|
72
|
+
previousResponse.answer_stage !== newResponse.answer_stage ||
|
|
73
|
+
lengthOf(previousResponse.answer) !== lengthOf(newResponse.answer) ||
|
|
74
|
+
lengthOf(previousResponse.reasoning) !== lengthOf(newResponse.reasoning);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function revisionOf(response) {
|
|
78
|
+
return response && response.revision;
|
|
79
|
+
}
|
|
80
|
+
|
|
76
81
|
function lengthOf(value = '') {
|
|
77
82
|
return value.length;
|
|
78
83
|
}
|
package/src/client.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
import { trimObj, Component, uuidv4, defineValues } from '@miso.ai/commons';
|
|
1
|
+
import { trimObj, Component, uuidv4, defineValues, isInBrowser } from '@miso.ai/commons';
|
|
2
2
|
import { root, register, init } from './root.js';
|
|
3
3
|
import { Api } from './api/index.js';
|
|
4
4
|
import Context from './context.js';
|
|
5
5
|
import * as helpers from './utils.js';
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
const currentScript = isInBrowser ? document.currentScript : undefined;
|
|
8
8
|
|
|
9
9
|
class MisoClient extends Component {
|
|
10
10
|
|
|
11
11
|
static attach() {
|
|
12
|
+
if (typeof window === 'undefined') {
|
|
13
|
+
console.warn(`MisoClient cannot be attached in non-browser environment.`);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
12
16
|
(window.MisoClients || (window.MisoClients = [])).push(MisoClient);
|
|
13
17
|
if (window.MisoClient) {
|
|
14
18
|
if (window.MisoClient !== MisoClient) {
|
|
@@ -65,6 +69,9 @@ class MisoClient extends Component {
|
|
|
65
69
|
return trimObj(options);
|
|
66
70
|
}
|
|
67
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Used by shopify plugin.
|
|
74
|
+
*/
|
|
68
75
|
_readConfigFromScriptUrl() {
|
|
69
76
|
const url = currentScript.src || currentScript.href; // might be <link> as well
|
|
70
77
|
const params = new URL(new Request(url).url).searchParams;
|
package/src/plugin/analytics.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// [browser only]
|
|
2
|
+
|
|
1
3
|
import { Component, UserEngagementObserver, UserActivityObserver, Stopwatch, trimObj, mergeInteractions } from '@miso.ai/commons';
|
|
2
4
|
|
|
3
5
|
const PLUGIN_ID = 'std:analytics';
|
|
@@ -150,6 +152,13 @@ class Analytics {
|
|
|
150
152
|
this._readyAt = undefined;
|
|
151
153
|
|
|
152
154
|
this.config();
|
|
155
|
+
|
|
156
|
+
this._engagedSeconds = 0;
|
|
157
|
+
this._engagementInterval = setInterval(() => {
|
|
158
|
+
if (this._plugin._engagement.engaged && this._readyAt) {
|
|
159
|
+
this._engagedSeconds += 1;
|
|
160
|
+
}
|
|
161
|
+
}, 1000);
|
|
153
162
|
}
|
|
154
163
|
|
|
155
164
|
_injectWorkflow(workflow) {
|
|
@@ -183,6 +192,8 @@ class Analytics {
|
|
|
183
192
|
this._startAt = Date.now();
|
|
184
193
|
this._loadingAt = undefined;
|
|
185
194
|
this._readyAt = undefined;
|
|
195
|
+
|
|
196
|
+
this._engagedSeconds = 0;
|
|
186
197
|
}
|
|
187
198
|
|
|
188
199
|
_handleLoading({ session } = {}) {
|
|
@@ -209,6 +220,7 @@ class Analytics {
|
|
|
209
220
|
user_engagement_time: state.userEngagementTime,
|
|
210
221
|
user_idle_time: state.userIdleTime,
|
|
211
222
|
user_waiting_time: state.userWaitingTime,
|
|
223
|
+
user_engagement_time_v2: state.userEngagementTimeV2,
|
|
212
224
|
},
|
|
213
225
|
},
|
|
214
226
|
});
|
|
@@ -229,6 +241,7 @@ class Analytics {
|
|
|
229
241
|
const loadingAt = this._loadingAt;
|
|
230
242
|
const readyAt = this._readyAt;
|
|
231
243
|
let userEngagementTime = 0, userIdleTime = 0, userWaitingTime = 0;
|
|
244
|
+
let userEngagementTimeV2 = this._engagedSeconds * 1000;
|
|
232
245
|
|
|
233
246
|
if (loadingAt !== undefined) {
|
|
234
247
|
userWaitingTime = currentTime - loadingAt;
|
|
@@ -244,6 +257,7 @@ class Analytics {
|
|
|
244
257
|
userWaitingTime,
|
|
245
258
|
userEngagementTime,
|
|
246
259
|
userIdleTime,
|
|
260
|
+
userEngagementTimeV2,
|
|
247
261
|
});
|
|
248
262
|
}
|
|
249
263
|
|
package/src/plugin/context.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { API, uuidv4, Component, delegateProperties, getOrComputeFromStorage, mergeInteractions, mergeApiPayloads } from '@miso.ai/commons';
|
|
1
|
+
import { API, uuidv4, Component, delegateProperties, getOrComputeFromStorage, mergeInteractions, mergeApiPayloads, isInBrowser } from '@miso.ai/commons';
|
|
2
2
|
|
|
3
3
|
const { GROUP, NAME } = API;
|
|
4
4
|
|
|
@@ -73,7 +73,7 @@ function getAutoAnonymousId() {
|
|
|
73
73
|
// 1. Cache the value for the page
|
|
74
74
|
// 2. Get and set the value from cookies/localStorage is possible
|
|
75
75
|
// 3. In case cookies/localStorage are disabled, generate a new value for each page
|
|
76
|
-
return _pageBasedAutoAnonymousId || (_pageBasedAutoAnonymousId = getOrComputeFromStorage('miso_anonymous_id', uuidv4));
|
|
76
|
+
return _pageBasedAutoAnonymousId || (_pageBasedAutoAnonymousId = isInBrowser ? getOrComputeFromStorage('miso_anonymous_id', uuidv4) : uuidv4());
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
class ClientContext {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isInBrowser } from '@miso.ai/commons';
|
|
2
|
+
|
|
1
3
|
const PLUGIN_ID = 'std:native-fetch';
|
|
2
4
|
|
|
3
5
|
function isNativeFunction(fn) {
|
|
@@ -8,6 +10,9 @@ let _fetchSource;
|
|
|
8
10
|
let _fetchError;
|
|
9
11
|
|
|
10
12
|
const fetchFn = (() => {
|
|
13
|
+
if (!isInBrowser) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
11
16
|
if (isNativeFunction(window.fetch)) {
|
|
12
17
|
_fetchSource = 'original';
|
|
13
18
|
return window.fetch;
|
|
@@ -32,6 +37,10 @@ export default class NativeFetchPlugin {
|
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
install(MisoClient, context) {
|
|
40
|
+
if (!isInBrowser) {
|
|
41
|
+
MisoClient.debug(`<plugin:${PLUGIN_ID}>`, '[info]', `Not in browser, skipped`);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
35
44
|
if (!fetchFn) {
|
|
36
45
|
MisoClient.debug(`<plugin:${PLUGIN_ID}>`, '[error]', `Failed to obtain native fetch: ${_fetchError.message}`);
|
|
37
46
|
return;
|
package/src/plugin/page-info.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { delegateGetters, defineValues, Registry, Resolution, Resources } from '@miso.ai/commons';
|
|
1
|
+
import { isInBrowser, delegateGetters, defineValues, Registry, Resolution, Resources } from '@miso.ai/commons';
|
|
2
2
|
import classes from '../classes.js';
|
|
3
3
|
import AnonymousPlugin from './anonymous.js';
|
|
4
4
|
import { getPluginScriptUrl } from './urls.js';
|
|
@@ -11,7 +11,6 @@ export default class PluginRoot extends Registry {
|
|
|
11
11
|
keyName: 'id',
|
|
12
12
|
});
|
|
13
13
|
this._root = root;
|
|
14
|
-
this._currentScript = document.currentScript;
|
|
15
14
|
this._events._replays.add('install').add('subtree');
|
|
16
15
|
this._installed = {};
|
|
17
16
|
this._installedResolutions = {};
|
|
@@ -122,6 +121,13 @@ export default class PluginRoot extends Registry {
|
|
|
122
121
|
this._root._customSendBeacon = sendBeacon;
|
|
123
122
|
}
|
|
124
123
|
|
|
124
|
+
setCustomApiIterator(customApiIterator) {
|
|
125
|
+
if (typeof customApiIterator !== 'function') {
|
|
126
|
+
throw new Error(`Expect parameter to be a function: ${customApiIterator}`);
|
|
127
|
+
}
|
|
128
|
+
this._root._customApiIterator = customApiIterator;
|
|
129
|
+
}
|
|
130
|
+
|
|
125
131
|
onHubUpdate(callback) {
|
|
126
132
|
if (typeof callback !== 'function') {
|
|
127
133
|
throw new Error(`Expect parameter to be a function: ${callback}`);
|
|
@@ -210,7 +216,7 @@ export default class PluginRoot extends Registry {
|
|
|
210
216
|
}
|
|
211
217
|
|
|
212
218
|
async _tryRegisterRemotely(id) {
|
|
213
|
-
if (id.startsWith('std:')) {
|
|
219
|
+
if (id.startsWith('std:') && isInBrowser) {
|
|
214
220
|
try {
|
|
215
221
|
await this._registerStdRemotely(id);
|
|
216
222
|
return;
|
|
@@ -222,6 +228,10 @@ export default class PluginRoot extends Registry {
|
|
|
222
228
|
throw new Error(`Cannot register plugin remotely: ${id}`);
|
|
223
229
|
}
|
|
224
230
|
|
|
231
|
+
/**
|
|
232
|
+
* [browser only]
|
|
233
|
+
* @param {string} id
|
|
234
|
+
*/
|
|
225
235
|
async _registerStdRemotely(id) {
|
|
226
236
|
const { version } = this._root;
|
|
227
237
|
const request = version === 'dev' ? `plugin:${id}@dev:${this.MisoClient.uuid}` : `plugin:${id}@${version}`;
|
|
@@ -231,7 +241,7 @@ export default class PluginRoot extends Registry {
|
|
|
231
241
|
// skip if already exists
|
|
232
242
|
const script = document.createElement('script');
|
|
233
243
|
script.async = true;
|
|
234
|
-
script.src = getPluginScriptUrl(id, version
|
|
244
|
+
script.src = getPluginScriptUrl(id, version);
|
|
235
245
|
script.setAttribute('data-request', request);
|
|
236
246
|
document.head.appendChild(script);
|
|
237
247
|
// TODO: hook up error event
|
|
@@ -250,7 +260,7 @@ export default class PluginRoot extends Registry {
|
|
|
250
260
|
class PluginContext {
|
|
251
261
|
|
|
252
262
|
constructor(root, classes) {
|
|
253
|
-
delegateGetters(this, root, ['getPluginClass', 'addSubtree', 'addPayloadPass', 'addHeadersPass', 'addUrlPass', 'setCustomFetch', 'setCustomSendBeacon', 'onHubUpdate', 'onHubEmit', 'whenInstalled', 'whenRegistered']);
|
|
263
|
+
delegateGetters(this, root, ['getPluginClass', 'addSubtree', 'addPayloadPass', 'addHeadersPass', 'addUrlPass', 'setCustomFetch', 'setCustomSendBeacon', 'setCustomApiIterator', 'onHubUpdate', 'onHubEmit', 'whenInstalled', 'whenRegistered']);
|
|
254
264
|
defineValues(this, { classes });
|
|
255
265
|
}
|
|
256
266
|
|
package/src/plugin/urls.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
import { isInBrowser } from '@miso.ai/commons';
|
|
2
|
+
|
|
3
|
+
const currentScript = isInBrowser ? document.currentScript : undefined;
|
|
4
|
+
|
|
5
|
+
export function getPluginScriptUrl(id, version) {
|
|
2
6
|
// TODO: look up by manifest
|
|
3
7
|
const pkgName = id.slice(4);
|
|
4
8
|
|
|
5
9
|
if (version === 'dev') {
|
|
10
|
+
if (!currentScript) {
|
|
11
|
+
throw new Error(`Cannot get plugin script URL for ${id}: no currentScript.`);
|
|
12
|
+
}
|
|
6
13
|
const src = currentScript.src;
|
|
7
14
|
const searchIndex = src.indexOf('?');
|
|
8
15
|
const k = searchIndex < 0 ? src.length : searchIndex;
|
package/src/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export default '1.13.
|
|
1
|
+
export default '1.13.1-beta.0';
|