@knowlearning/agents 0.9.25 → 0.9.27

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.
@@ -38,22 +38,19 @@ export default function EmbeddedAgent() {
38
38
  }
39
39
 
40
40
  addEventListener('message', async ({ data }) => {
41
- if (data.type === 'auth') {
42
- // TODO: switch to access_token
43
- if (localStorage.getItem('state') === data.state) {
44
- localStorage.setItem('token', data.token)
45
- }
46
- send({ type: 'close' })
47
- }
48
- else if (data.type === 'setup') resolveSession(data.session)
41
+ if (data.type === 'setup') resolveSession(data.session)
49
42
  else if (responses[data.requestId]) {
50
43
  const { resolve, reject } = responses[data.requestId]
51
44
  if (data.error) reject(data.error)
52
45
  else resolve(data.response)
53
46
  }
54
47
  else if (data.ii !== undefined) {
55
- const { scope } = data
56
- if (watchers[scope]) watchers[scope].forEach(fn => fn(data))
48
+ const { scope, user, domain } = data
49
+ const { auth, domain:rootDomain } = await environment()
50
+ const d = !domain || domain === rootDomain ? '' : domain
51
+ const u = !user || auth.user === user ? '' : user
52
+ const key = isUUID(scope) ? scope : `${d}/${u}/${scope}`
53
+ if (watchers[key]) watchers[key].forEach(fn => fn(data))
57
54
  }
58
55
  })
59
56
 
@@ -62,9 +59,11 @@ export default function EmbeddedAgent() {
62
59
  }
63
60
 
64
61
  function create({ id=uuid(), active_type, active }) {
65
- // TODO: collapse into 1 patch and 1 interact call
66
- interact(id, [{ op: 'add', path: ['active_type'], value: active_type }])
67
- interact(id, [{ op: 'add', path: ['active'], value: active }])
62
+ if (!active_type) active_type = 'application/json'
63
+ interact(id, [
64
+ { op: 'add', path: ['active_type'], value: active_type },
65
+ { op: 'add', path: ['active'], value: active }
66
+ ])
68
67
  return id
69
68
  }
70
69
 
@@ -83,12 +82,13 @@ export default function EmbeddedAgent() {
83
82
  await tag(tag_type, target)
84
83
  }
85
84
 
86
-
87
- function watch(id, fn) {
88
- tagIfNotYetTaggedInSession('subscribed', id)
89
- if (!watchers[id]) watchers[id] = []
90
- watchers[id].push(fn)
91
- return () => removeWatcher(id, fn)
85
+ function watch(scope, fn, user, domain) {
86
+ tagIfNotYetTaggedInSession('subscribed', scope)
87
+ const key = isUUID(scope) ? scope : `${ domain || ''}/${ user || ''}/${scope}`
88
+ if (!watchers[key]) watchers[key] = []
89
+ watchers[key].push(fn)
90
+ send({ type: 'state', scope, user, domain })
91
+ return () => removeWatcher(key, fn)
92
92
  }
93
93
 
94
94
  async function patch(root, scopes) {
@@ -96,19 +96,19 @@ export default function EmbeddedAgent() {
96
96
  return send({ type: 'patch', root, scopes })
97
97
  }
98
98
 
99
- async function state(scope) {
99
+ async function state(scope, user, domain) {
100
100
  if (scope === undefined) {
101
101
  const { context } = await environment()
102
102
  scope = JSON.stringify(context)
103
103
  }
104
104
  tagIfNotYetTaggedInSession('subscribed', scope)
105
- const startState = await send({ type: 'state', scope })
105
+ const startState = await send({ type: 'state', scope, user, domain })
106
106
  return new MutableProxy(startState, patch => {
107
+ // TODO: reject updates if user is not owner
107
108
  const activePatch = structuredClone(patch)
108
109
  activePatch.forEach(entry => entry.path.unshift('active'))
109
110
  interact(scope, activePatch)
110
111
  })
111
-
112
112
  }
113
113
 
114
114
  function reset(scope) {
@@ -4,15 +4,15 @@ import { v1 as uuid, validate as validateUUID } from 'uuid'
4
4
 
5
5
  let Agent
6
6
 
7
- export default function browserAgent() {
8
- if (Agent) return Agent
7
+ export default function browserAgent(options={}) {
8
+ if (Agent && !options.unique) return Agent
9
9
 
10
10
  let embedded
11
11
 
12
12
  try { embedded = window.self !== window.top }
13
13
  catch (e) { embedded = true }
14
14
 
15
- Agent = embedded ? EmbeddedAgent() : RootAgent()
15
+ Agent = embedded && !options.root ? EmbeddedAgent() : RootAgent(options)
16
16
  Agent.embed = embed
17
17
 
18
18
  return Agent
@@ -71,7 +71,8 @@ function embed(environment, iframe) {
71
71
  sendDown({}) // TODO: might want to send down the interaction index
72
72
  }
73
73
  else if (type === 'metadata') {
74
- sendDown(await Agent.metadata(message.scope))
74
+ const { scope, user } = message
75
+ sendDown(await Agent.metadata(scope, user))
75
76
  }
76
77
  else if (type === 'tag') {
77
78
  const { tag_type, target, context } = message
@@ -79,11 +80,14 @@ function embed(environment, iframe) {
79
80
  sendDown(await Agent.tag(tag_type, target, prependedContext))
80
81
  }
81
82
  else if (type === 'state') {
82
- const { scope } = message
83
+ const { scope, user, domain } = message
83
84
 
84
- const statePromise = Agent.state(scope)
85
+ const statePromise = Agent.state(scope, user, domain)
85
86
 
86
- if (!watchers[scope]) watchers[scope] = Agent.watch(scope, postMessage)
87
+ const key = `${ domain || ''}/${user || ''}/${scope}`
88
+ if (!watchers[key]) {
89
+ watchers[key] = Agent.watch(scope, postMessage, user, domain)
90
+ }
87
91
 
88
92
  if (listeners.state) listeners.state({ scope })
89
93
  sendDown(await statePromise)
@@ -8,13 +8,13 @@ const REMOTE_HOST = 'api.knowlearning.systems'
8
8
 
9
9
  function isLocal() { return localStorage.getItem('api') === 'local' }
10
10
 
11
- export default () => {
11
+ export default options => {
12
12
  const { host, protocol } = window.location
13
13
 
14
14
  const agent = GenericAgent({
15
15
  host: isLocal() ? DEVELOPMENT_HOST : REMOTE_HOST,
16
16
  protocol: protocol === 'https:' ? 'wss' : 'ws',
17
- token: getToken,
17
+ token: options.getToken || getToken,
18
18
  WebSocket,
19
19
  uuid,
20
20
  fetch,
@@ -51,7 +51,7 @@ export default function Agent({ host, token, WebSocket, protocol='ws', uuid, fet
51
51
 
52
52
  async function environment() { return { ...(await environmentPromise), context: [] } }
53
53
 
54
- function state(scope, user) { return stateImplementation(scope, user, internalReferences) }
54
+ function state(scope, user, domain) { return stateImplementation(scope, user, domain, internalReferences) }
55
55
 
56
56
  function download(id) { return downloadImplementation(id, internalReferences) }
57
57
 
@@ -60,6 +60,7 @@ export default function Agent({ host, token, WebSocket, protocol='ws', uuid, fet
60
60
  function log() { if (mode === 'debug') console.log(...arguments) }
61
61
 
62
62
  function create({ id=uuid(), active_type, active, name }) {
63
+ if (!active_type) active_type = 'application/json'
63
64
  const patch = [
64
65
  { op: 'add', path: ['active_type'], value: active_type },
65
66
  { op: 'add', path: ['active'], value: active }
@@ -110,7 +111,7 @@ export default function Agent({ host, token, WebSocket, protocol='ws', uuid, fet
110
111
  const response = queueMessage({scope, patch})
111
112
 
112
113
  // if we are watching this scope, we want to keep track of last interaction we fired
113
- const qualifiedScope = isUUID(scope) ? scope : `/${scope}`
114
+ const qualifiedScope = isUUID(scope) ? scope : `//${scope}`
114
115
  if (states[qualifiedScope] !== undefined) {
115
116
  let resolve
116
117
  lastInteractionResponse[qualifiedScope] = new Promise(r => resolve = r)
@@ -170,7 +170,10 @@ export default function messageQueue(setEnvironment, { token, protocol, host, We
170
170
  }
171
171
  }
172
172
  else {
173
- const qualifiedScope = isUUID(message.scope) ? message.scope : `${ message.user === user ? '' : message.user}/${message.scope}`
173
+ const d = message.domain === window.location.host ? '' : message.domain
174
+ const u = message.user === user ? '' : message.user
175
+ const s = message.scope
176
+ const qualifiedScope = isUUID(s) ? s : `${d}/${u}/${s}`
174
177
  if (watchers[qualifiedScope]) {
175
178
  states[qualifiedScope] = await states[qualifiedScope]
176
179
 
@@ -3,12 +3,12 @@ import MutableProxy from '../../persistence/json.js'
3
3
 
4
4
  const SUBSCRIPTION_TYPE = 'application/json;type=subscription'
5
5
 
6
- export default function(scope='[]', user, { keyToSubscriptionId, watchers, states, create, environment, lastMessageResponse, lastInteractionResponse, tagIfNotYetTaggedInSession, interact }) {
6
+ export default function(scope='[]', user, domain, { keyToSubscriptionId, watchers, states, create, environment, lastMessageResponse, lastInteractionResponse, tagIfNotYetTaggedInSession, interact }) {
7
7
  let resolveMetadataPromise
8
8
  let metadataPromise = new Promise(resolve => resolveMetadataPromise = resolve)
9
9
 
10
10
  const statePromise = new Promise(async (resolveState, rejectState) => {
11
- const qualifiedScope = isUUID(scope) ? scope : `${user || ''}/${scope}`
11
+ const qualifiedScope = isUUID(scope) ? scope : `${domain || ''}/${user || ''}/${scope}`
12
12
  if (!keyToSubscriptionId[qualifiedScope]) {
13
13
  const id = uuid()
14
14
 
@@ -19,7 +19,7 @@ export default function(scope='[]', user, { keyToSubscriptionId, watchers, state
19
19
  create({
20
20
  id,
21
21
  active_type: SUBSCRIPTION_TYPE,
22
- active: { session, scope, user, ii: null, initialized: Date.now() },
22
+ active: { session, scope, user, domain, ii: null, initialized: Date.now() },
23
23
  })
24
24
 
25
25
  try {
@@ -2,8 +2,8 @@ import { validate as isUUID } from 'uuid'
2
2
 
3
3
  export default function({ metadata, state, watchers }) {
4
4
 
5
- function watch(scope=DEFAULT_SCOPE_NAME, fn, user) {
6
- if (Array.isArray(scope)) return watchResolution(scope, fn, user)
5
+ function watch(scope=DEFAULT_SCOPE_NAME, fn, user, domain) {
6
+ if (Array.isArray(scope)) return watchResolution(scope, fn, user, domain)
7
7
 
8
8
  let initialSent = false
9
9
  const queue = []
@@ -12,16 +12,18 @@ export default function({ metadata, state, watchers }) {
12
12
  else queue.push(update)
13
13
  }
14
14
 
15
- const statePromise = state(scope, user)
16
- const qualifiedScope = isUUID(scope) ? scope : `${user || ''}/${scope}`
15
+ const statePromise = state(scope, user, domain)
16
+ const qualifiedScope = isUUID(scope) ? scope : `${domain || ''}/${user || ''}/${scope}`
17
17
 
18
18
  if (!watchers[qualifiedScope]) watchers[qualifiedScope] = []
19
19
  watchers[qualifiedScope].push(cb)
20
20
 
21
- metadata(scope, user)
21
+ metadata(scope, user, domain)
22
22
  .then(async ({ ii }) => {
23
23
  fn({
24
24
  scope,
25
+ user,
26
+ domain,
25
27
  state: await statePromise,
26
28
  patch: null,
27
29
  ii
@@ -33,7 +35,7 @@ export default function({ metadata, state, watchers }) {
33
35
  return () => removeWatcher(qualifiedScope, cb)
34
36
  }
35
37
 
36
- function watchResolution(path, callback, user) {
38
+ function watchResolution(path, callback, user, domain) {
37
39
  const id = path[0]
38
40
  const references = path.slice(1)
39
41
  let unwatchDeeper = () => {}
@@ -57,13 +59,13 @@ export default function({ metadata, state, watchers }) {
57
59
  index === references.length - 1
58
60
  ) callback(value)
59
61
  else if (isUUID(value)) {
60
- unwatchDeeper = watchResolution([value, ...references.slice(index + 1)], callback, user)
62
+ unwatchDeeper = watchResolution([value, ...references.slice(index + 1)], callback, user, domain)
61
63
  return
62
64
  }
63
65
  }
64
66
  }
65
67
 
66
- const unwatch = watch(id, watchCallback, user)
68
+ const unwatch = watch(id, watchCallback, user, domain)
67
69
 
68
70
  return () => {
69
71
  unwatch()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knowlearning/agents",
3
- "version": "0.9.25",
3
+ "version": "0.9.27",
4
4
  "description": "API for embedding applications in KnowLearning systems.",
5
5
  "main": "node.js",
6
6
  "browser": "browser.js",