@knowlearning/agents 0.9.27 → 0.9.28
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.
|
@@ -7,6 +7,7 @@ export default function EmbeddedAgent() {
|
|
|
7
7
|
const session = new Promise(r => resolveSession = r)
|
|
8
8
|
const responses = {}
|
|
9
9
|
const watchers = {}
|
|
10
|
+
const sentUpdates = {}
|
|
10
11
|
|
|
11
12
|
function removeWatcher(key, fn) {
|
|
12
13
|
const watcherIndex = watchers[key].findIndex(x => x === fn)
|
|
@@ -37,8 +38,13 @@ export default function EmbeddedAgent() {
|
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
let sessionResolved = false
|
|
40
42
|
addEventListener('message', async ({ data }) => {
|
|
41
|
-
if (data.type === 'setup')
|
|
43
|
+
if (data.type === 'setup' && !sessionResolved) {
|
|
44
|
+
sessionResolved = true
|
|
45
|
+
resolveSession(data.session)
|
|
46
|
+
}
|
|
47
|
+
else if (!sessionResolved || data.session !== await session) return
|
|
42
48
|
else if (responses[data.requestId]) {
|
|
43
49
|
const { resolve, reject } = responses[data.requestId]
|
|
44
50
|
if (data.error) reject(data.error)
|
|
@@ -50,7 +56,15 @@ export default function EmbeddedAgent() {
|
|
|
50
56
|
const d = !domain || domain === rootDomain ? '' : domain
|
|
51
57
|
const u = !user || auth.user === user ? '' : user
|
|
52
58
|
const key = isUUID(scope) ? scope : `${d}/${u}/${scope}`
|
|
53
|
-
if (watchers[key])
|
|
59
|
+
if (watchers[key]) {
|
|
60
|
+
if (sentUpdates[key] + 1 === data.ii) {
|
|
61
|
+
sentUpdates[key] = data.ii
|
|
62
|
+
watchers[key].forEach(fn => fn(data))
|
|
63
|
+
}
|
|
64
|
+
else if (data.ii !== sentUpdates[key]) {
|
|
65
|
+
console.warn('Out of order or repeated update for', key, data.ii, sentUpdates[key])
|
|
66
|
+
}
|
|
67
|
+
}
|
|
54
68
|
}
|
|
55
69
|
})
|
|
56
70
|
|
|
@@ -84,11 +98,24 @@ export default function EmbeddedAgent() {
|
|
|
84
98
|
|
|
85
99
|
function watch(scope, fn, user, domain) {
|
|
86
100
|
tagIfNotYetTaggedInSession('subscribed', scope)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
101
|
+
|
|
102
|
+
const key = (
|
|
103
|
+
environment()
|
|
104
|
+
.then(async ({ auth, domain:rootDomain }) => {
|
|
105
|
+
const d = !domain || domain === rootDomain ? '' : domain
|
|
106
|
+
const u = !user || auth.user === user ? '' : user
|
|
107
|
+
const key = isUUID(scope) ? scope : `${d}/${u}/${scope}`
|
|
108
|
+
|
|
109
|
+
const state = await send({ type: 'state', scope, user, domain })
|
|
110
|
+
const metadata = await send({ type: 'metadata', scope, user, domain })
|
|
111
|
+
fn({ state, patch: null, ii: metadata.ii })
|
|
112
|
+
sentUpdates[key] = metadata.ii
|
|
113
|
+
if (!watchers[key]) watchers[key] = []
|
|
114
|
+
watchers[key].push(fn)
|
|
115
|
+
return key
|
|
116
|
+
})
|
|
117
|
+
)
|
|
118
|
+
return async () => removeWatcher(await key, fn)
|
|
92
119
|
}
|
|
93
120
|
|
|
94
121
|
async function patch(root, scopes) {
|
|
@@ -12,10 +12,12 @@ export default function browserAgent(options={}) {
|
|
|
12
12
|
try { embedded = window.self !== window.top }
|
|
13
13
|
catch (e) { embedded = true }
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const newAgent = embedded && !options.root ? EmbeddedAgent() : RootAgent(options)
|
|
16
|
+
newAgent.embed = embed
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
if (!Agent) Agent = newAgent
|
|
19
|
+
|
|
20
|
+
return newAgent
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
const copy = x => JSON.parse(JSON.stringify(x))
|
|
@@ -57,10 +59,9 @@ function embed(environment, iframe) {
|
|
|
57
59
|
if (listeners.close) listeners.close(message.info)
|
|
58
60
|
}
|
|
59
61
|
else if (type === 'environment') {
|
|
62
|
+
const { context } = message
|
|
60
63
|
const env = await Agent.environment()
|
|
61
|
-
|
|
62
|
-
Object.assign(env, { ...env, context })
|
|
63
|
-
sendDown(env)
|
|
64
|
+
sendDown({ ...env, context: [...env.context, environment.id] })
|
|
64
65
|
}
|
|
65
66
|
else if (type === 'interact') {
|
|
66
67
|
const { scope, patch } = message
|
|
@@ -154,6 +155,7 @@ function embed(environment, iframe) {
|
|
|
154
155
|
else iframe.src = id // TODO: ensure is url
|
|
155
156
|
|
|
156
157
|
while(!embeddedAgentInitialized) {
|
|
158
|
+
// TODO: wait for any other agents that are initializing from other potential root agents
|
|
157
159
|
postMessage({ type: 'setup', session })
|
|
158
160
|
await new Promise(r => setTimeout(r, 100))
|
|
159
161
|
}
|
package/agents/generic/index.js
CHANGED
|
@@ -18,7 +18,6 @@ export default function messageQueue(setEnvironment, { token, protocol, host, We
|
|
|
18
18
|
let ws
|
|
19
19
|
let user
|
|
20
20
|
let authed = false
|
|
21
|
-
let isSynced = false
|
|
22
21
|
let session
|
|
23
22
|
let server
|
|
24
23
|
let si = -1
|
|
@@ -30,7 +29,7 @@ export default function messageQueue(setEnvironment, { token, protocol, host, We
|
|
|
30
29
|
let lastSynchronousScopePatchPromise = null
|
|
31
30
|
let restarting = false
|
|
32
31
|
let disconnected = false
|
|
33
|
-
const
|
|
32
|
+
const outstandingSyncPromises = []
|
|
34
33
|
const responses = {}
|
|
35
34
|
|
|
36
35
|
|
|
@@ -41,7 +40,6 @@ export default function messageQueue(setEnvironment, { token, protocol, host, We
|
|
|
41
40
|
}
|
|
42
41
|
|
|
43
42
|
function queueMessage({ scope, patch }) {
|
|
44
|
-
isSynced = false
|
|
45
43
|
if (lastSynchronousScopePatched === scope) {
|
|
46
44
|
const i = messageQueue.length - 1
|
|
47
45
|
messageQueue[i].patch = [...messageQueue[i].patch, ...patch]
|
|
@@ -74,8 +72,10 @@ export default function messageQueue(setEnvironment, { token, protocol, host, We
|
|
|
74
72
|
}
|
|
75
73
|
|
|
76
74
|
function resolveSyncPromises() {
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
const lowestOutstandingResponseIndex = Object.keys(responses).map(parseInt).sort()[0] || Infinity
|
|
76
|
+
while (outstandingSyncPromises[0] && outstandingSyncPromises[0].si < lowestOutstandingResponseIndex) {
|
|
77
|
+
outstandingSyncPromises.shift().resolve()
|
|
78
|
+
}
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
function checkHeartbeat() {
|
|
@@ -162,7 +162,7 @@ export default function messageQueue(setEnvironment, { token, protocol, host, We
|
|
|
162
162
|
|
|
163
163
|
delete responses[message.si]
|
|
164
164
|
ws.send(JSON.stringify({ack: message.si})) // acknowledgement that we have received the response for this message
|
|
165
|
-
|
|
165
|
+
resolveSyncPromises()
|
|
166
166
|
}
|
|
167
167
|
else {
|
|
168
168
|
// TODO: consider what to do here... probably want to throw error if in dev env
|
|
@@ -208,7 +208,11 @@ export default function messageQueue(setEnvironment, { token, protocol, host, We
|
|
|
208
208
|
checkHeartbeat()
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
async function synced() {
|
|
211
|
+
async function synced() {
|
|
212
|
+
const syncPromise = new Promise(resolve => outstandingSyncPromises.push({ si: lastSentSI, resolve }))
|
|
213
|
+
resolveSyncPromises()
|
|
214
|
+
return syncPromise
|
|
215
|
+
}
|
|
212
216
|
|
|
213
217
|
function lastMessageResponse() { return new Promise((res, rej) => responses[si].push([res, rej])) }
|
|
214
218
|
|
package/agents/generic/watch.js
CHANGED
|
@@ -1,23 +1,13 @@
|
|
|
1
1
|
import { validate as isUUID } from 'uuid'
|
|
2
2
|
|
|
3
|
-
export default function({ metadata, state, watchers }) {
|
|
3
|
+
export default function({ metadata, state, watchers, synced }) {
|
|
4
4
|
|
|
5
5
|
function watch(scope=DEFAULT_SCOPE_NAME, fn, user, domain) {
|
|
6
6
|
if (Array.isArray(scope)) return watchResolution(scope, fn, user, domain)
|
|
7
7
|
|
|
8
|
-
let initialSent = false
|
|
9
|
-
const queue = []
|
|
10
|
-
function cb(update) {
|
|
11
|
-
if (initialSent) fn(update)
|
|
12
|
-
else queue.push(update)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
8
|
const statePromise = state(scope, user, domain)
|
|
16
9
|
const qualifiedScope = isUUID(scope) ? scope : `${domain || ''}/${user || ''}/${scope}`
|
|
17
10
|
|
|
18
|
-
if (!watchers[qualifiedScope]) watchers[qualifiedScope] = []
|
|
19
|
-
watchers[qualifiedScope].push(cb)
|
|
20
|
-
|
|
21
11
|
metadata(scope, user, domain)
|
|
22
12
|
.then(async ({ ii }) => {
|
|
23
13
|
fn({
|
|
@@ -28,11 +18,11 @@ export default function({ metadata, state, watchers }) {
|
|
|
28
18
|
patch: null,
|
|
29
19
|
ii
|
|
30
20
|
})
|
|
31
|
-
|
|
32
|
-
|
|
21
|
+
if (!watchers[qualifiedScope]) watchers[qualifiedScope] = []
|
|
22
|
+
watchers[qualifiedScope].push(fn)
|
|
33
23
|
})
|
|
34
24
|
|
|
35
|
-
return () => removeWatcher(qualifiedScope,
|
|
25
|
+
return () => removeWatcher(qualifiedScope, fn)
|
|
36
26
|
}
|
|
37
27
|
|
|
38
28
|
function watchResolution(path, callback, user, domain) {
|