@knowlearning/agents 0.9.29 → 0.9.31

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.
@@ -1,4 +1,5 @@
1
1
  import { validate as isUUID, v1 as uuid } from 'uuid'
2
+ import watchImplementation from '../watch.js'
2
3
  import MutableProxy from '../../persistence/json.js'
3
4
 
4
5
  export default function EmbeddedAgent() {
@@ -9,11 +10,7 @@ export default function EmbeddedAgent() {
9
10
  const watchers = {}
10
11
  const sentUpdates = {}
11
12
 
12
- function removeWatcher(key, fn) {
13
- const watcherIndex = watchers[key].findIndex(x => x === fn)
14
- if (watcherIndex > -1) watchers[key].splice(watcherIndex, 1)
15
- else console.warn('TRIED TO REMOVE WATCHER THAT DOES NOT EXIST')
16
- }
13
+ const [ watch, removeWatcher ] = watchImplementation({ metadata, state, watchers, synced, sentUpdates, environment })
17
14
 
18
15
  async function send(message) {
19
16
  const requestId = message.requestId || uuid()
@@ -56,13 +53,18 @@ export default function EmbeddedAgent() {
56
53
  const d = !domain || domain === rootDomain ? '' : domain
57
54
  const u = !user || auth.user === user ? '' : user
58
55
  const key = isUUID(scope) ? scope : `${d}/${u}/${scope}`
56
+
57
+ const sendUpdate = () => {
58
+ sentUpdates[key] = data.ii
59
+ watchers[key].forEach(fn => fn(data))
60
+ }
61
+
59
62
  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])
63
+ if (sentUpdates[key] === undefined || sentUpdates[key] + 1 === data.ii) sendUpdate()
64
+ else if (data.ii === sentUpdates[key]) console.warn('Repeated update for', key, data, sentUpdates[key])
65
+ else {
66
+ console.warn('Out of order update for', key, data, sentUpdates[key])
67
+ if (data.ii > sentUpdates[key]) sendUpdate()
66
68
  }
67
69
  }
68
70
  }
@@ -96,37 +98,6 @@ export default function EmbeddedAgent() {
96
98
  await tag(tag_type, target)
97
99
  }
98
100
 
99
- function watch(scope, fn, user, domain) {
100
- let watchingPath = false
101
- if (scope && scope.length === 1) {
102
- watchingPath = true
103
- scope = scope[0]
104
- }
105
- // TODO: actually allow watching at paths in embedded
106
-
107
- tagIfNotYetTaggedInSession('subscribed', scope)
108
-
109
- const wrappedFn = update => fn(watchingPath ? update.state : update)
110
-
111
- const key = (
112
- environment()
113
- .then(async ({ auth, domain:rootDomain }) => {
114
- const d = !domain || domain === rootDomain ? '' : domain
115
- const u = !user || auth.user === user ? '' : user
116
- const key = isUUID(scope) ? scope : `${d}/${u}/${scope}`
117
-
118
- const state = await send({ type: 'state', scope, user, domain })
119
- const metadata = await send({ type: 'metadata', scope, user, domain })
120
- wrappedFn({ state, patch: null, ii: metadata.ii })
121
- sentUpdates[key] = metadata.ii
122
- if (!watchers[key]) watchers[key] = []
123
- watchers[key].push(wrappedFn)
124
- return key
125
- })
126
- )
127
- return async () => removeWatcher(await key, wrappedFn)
128
- }
129
-
130
101
  async function patch(root, scopes) {
131
102
  // TODO: consider watch function added to return to receive progress
132
103
  return send({ type: 'patch', root, scopes })
@@ -221,8 +192,8 @@ export default function EmbeddedAgent() {
221
192
  )
222
193
  }
223
194
 
224
- async function metadata(scope) {
225
- const md = await send({ type: 'metadata', scope })
195
+ async function metadata(scope, user, domain) {
196
+ const md = await send({ type: 'metadata', scope, user, domain })
226
197
  return new MutableProxy(md, patch => {
227
198
  const activePatch = structuredClone(patch)
228
199
  activePatch.forEach(entry => {
@@ -72,8 +72,8 @@ function embed(environment, iframe) {
72
72
  sendDown({}) // TODO: might want to send down the interaction index
73
73
  }
74
74
  else if (type === 'metadata') {
75
- const { scope, user } = message
76
- sendDown(await Agent.metadata(scope, user))
75
+ const { scope, user, domain } = message
76
+ sendDown(await Agent.metadata(scope, user, domain))
77
77
  }
78
78
  else if (type === 'tag') {
79
79
  const { tag_type, target, context } = message
@@ -2,7 +2,7 @@ import { validate as isUUID } from 'uuid'
2
2
  import MutableProxy from '../../persistence/json.js'
3
3
  import messageQueue from './message-queue.js'
4
4
  import stateImplementation from './state.js'
5
- import watchImplementation from './watch.js'
5
+ import watchImplementation from '../watch.js'
6
6
  import downloadImplementation from '../download.js'
7
7
 
8
8
  // TODO: consider using something better than name as mechanism
@@ -157,7 +157,7 @@ export default function Agent({ host, token, WebSocket, protocol='ws', uuid, fet
157
157
  )
158
158
  }
159
159
 
160
- async function metadata(id=DEFAULT_SCOPE_NAME, user) {
160
+ async function metadata(id=DEFAULT_SCOPE_NAME, user, domain) {
161
161
  const md = structuredClone(await state(id, user).metadata)
162
162
  delete md.active
163
163
  return new MutableProxy(md, patch => {
@@ -1,15 +1,23 @@
1
1
  import { validate as isUUID } from 'uuid'
2
2
 
3
- export default function({ metadata, state, watchers, synced }) {
3
+ const DEFAULT_SCOPE_NAME = '[]'
4
+
5
+ export default function({ metadata, environment, state, watchers, synced, sentUpdates }) {
4
6
 
5
7
  function watch(scope=DEFAULT_SCOPE_NAME, fn, user, domain) {
6
8
  if (Array.isArray(scope)) return watchResolution(scope, fn, user, domain)
7
9
 
8
10
  const statePromise = state(scope, user, domain)
9
- const qualifiedScope = isUUID(scope) ? scope : `${domain || ''}/${user || ''}/${scope}`
10
11
 
12
+ let qualifiedScope
13
+ let removed = false
11
14
  metadata(scope, user, domain)
12
15
  .then(async ({ ii }) => {
16
+ if (removed) return
17
+
18
+ const { auth: { user: u }, domain: d } = await environment()
19
+ qualifiedScope = isUUID(scope) ? scope : `${!domain || domain === d ? '' : domain}/${!user || user === u ? '' : user}/${scope}`
20
+
13
21
  fn({
14
22
  scope,
15
23
  user,
@@ -18,11 +26,19 @@ export default function({ metadata, state, watchers, synced }) {
18
26
  patch: null,
19
27
  ii
20
28
  })
29
+
30
+ if (sentUpdates) sentUpdates[qualifiedScope] = ii
31
+
32
+ if (removed) return
33
+
21
34
  if (!watchers[qualifiedScope]) watchers[qualifiedScope] = []
22
35
  watchers[qualifiedScope].push(fn)
23
36
  })
24
37
 
25
- return () => removeWatcher(qualifiedScope, fn)
38
+ return () => {
39
+ removed = true
40
+ return removeWatcher(qualifiedScope, fn)
41
+ }
26
42
  }
27
43
 
28
44
  function watchResolution(path, callback, user, domain) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knowlearning/agents",
3
- "version": "0.9.29",
3
+ "version": "0.9.31",
4
4
  "description": "API for embedding applications in KnowLearning systems.",
5
5
  "main": "node.js",
6
6
  "browser": "browser.js",