@knowlearning/agents 0.9.187 → 0.9.189
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/agents/attach-synced.js +56 -0
- package/agents/embedded.js +24 -12
- package/agents/generic/index.js +2 -0
- package/agents/generic/state.js +9 -5
- package/agents/sync.js +7 -0
- package/package.json +1 -1
- package/types.d.ts +6 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { applyPatch } from 'fast-json-patch'
|
|
2
|
+
import { standardJSONPatch } from '@knowlearning/patch-proxy'
|
|
3
|
+
|
|
4
|
+
// Wraps a state promise with a .synced(callback?) method that applies external
|
|
5
|
+
// patches to the live proxy in-place.
|
|
6
|
+
//
|
|
7
|
+
// Usage:
|
|
8
|
+
// const promise = attachSynced(watchers, (ctx, resolve) => {
|
|
9
|
+
// const p = new Promise(async (...) => {
|
|
10
|
+
// const proxy = new PatchProxy(data, patch => {
|
|
11
|
+
// if (ctx.applyingExternalUpdate) return
|
|
12
|
+
// // ... interact
|
|
13
|
+
// })
|
|
14
|
+
// resolve(proxy, qualifiedKey)
|
|
15
|
+
// resolvePromise(proxy)
|
|
16
|
+
// })
|
|
17
|
+
// return p
|
|
18
|
+
// })
|
|
19
|
+
export default function attachSynced(watchers, init) {
|
|
20
|
+
const ctx = { applyingExternalUpdate: false }
|
|
21
|
+
let shouldSync = false
|
|
22
|
+
let syncCallbacks = []
|
|
23
|
+
let syncRegistered = false
|
|
24
|
+
let resolvedProxy = null
|
|
25
|
+
let resolvedKey = null
|
|
26
|
+
|
|
27
|
+
function registerSyncWatcher() {
|
|
28
|
+
if (syncRegistered) return
|
|
29
|
+
syncRegistered = true
|
|
30
|
+
if (!watchers[resolvedKey]) watchers[resolvedKey] = []
|
|
31
|
+
watchers[resolvedKey].push(({ patch }) => {
|
|
32
|
+
if (!patch) return
|
|
33
|
+
ctx.applyingExternalUpdate = true
|
|
34
|
+
applyPatch(resolvedProxy, standardJSONPatch(patch))
|
|
35
|
+
ctx.applyingExternalUpdate = false
|
|
36
|
+
syncCallbacks.forEach(cb => cb(resolvedProxy, patch))
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function resolve(proxy, key) {
|
|
41
|
+
resolvedProxy = proxy
|
|
42
|
+
resolvedKey = key
|
|
43
|
+
if (shouldSync) registerSyncWatcher()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const promise = init(ctx, resolve)
|
|
47
|
+
|
|
48
|
+
promise.synced = function(callback) {
|
|
49
|
+
shouldSync = true
|
|
50
|
+
if (callback) syncCallbacks.push(callback)
|
|
51
|
+
if (resolvedProxy) registerSyncWatcher()
|
|
52
|
+
return promise
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return promise
|
|
56
|
+
}
|
package/agents/embedded.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { validate as isUUID, v1 as uuid } from 'uuid'
|
|
2
2
|
import PatchProxy from '@knowlearning/patch-proxy'
|
|
3
|
+
import attachSynced from './attach-synced.js'
|
|
3
4
|
import watchImplementation from './watch.js'
|
|
5
|
+
import sync from './sync.js'
|
|
4
6
|
|
|
5
7
|
export default function EmbeddedAgent(postMessage) {
|
|
6
8
|
let messageIndex = 0
|
|
@@ -95,18 +97,27 @@ export default function EmbeddedAgent(postMessage) {
|
|
|
95
97
|
return send({ type: 'patch', root, scopes })
|
|
96
98
|
}
|
|
97
99
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
100
|
+
function state(scope, user, domain) {
|
|
101
|
+
return attachSynced(watchers, (ctx, resolveSync) => (async () => {
|
|
102
|
+
if (scope === undefined) {
|
|
103
|
+
const { context } = await environment()
|
|
104
|
+
scope = JSON.stringify(context)
|
|
105
|
+
}
|
|
106
|
+
const startState = await send({ type: 'state', scope, user, domain })
|
|
107
|
+
const { auth, domain: rootDomain } = await environment()
|
|
108
|
+
const d = !domain || domain === rootDomain ? '' : domain
|
|
109
|
+
const u = !user || auth.user === user ? '' : user
|
|
110
|
+
const key = isUUID(scope) ? scope : `${d}/${u}/${scope}`
|
|
111
|
+
const proxy = new PatchProxy(startState, patch => {
|
|
112
|
+
// TODO: reject updates if user is not owner
|
|
113
|
+
if (ctx.applyingExternalUpdate) return
|
|
114
|
+
const activePatch = structuredClone(patch)
|
|
115
|
+
activePatch.forEach(entry => entry.path.unshift('active'))
|
|
116
|
+
interact(scope, activePatch)
|
|
117
|
+
})
|
|
118
|
+
resolveSync(proxy, key)
|
|
119
|
+
return proxy
|
|
120
|
+
})())
|
|
110
121
|
}
|
|
111
122
|
|
|
112
123
|
function reset(scope) {
|
|
@@ -227,6 +238,7 @@ export default function EmbeddedAgent(postMessage) {
|
|
|
227
238
|
synced,
|
|
228
239
|
close,
|
|
229
240
|
response,
|
|
241
|
+
sync,
|
|
230
242
|
query
|
|
231
243
|
}
|
|
232
244
|
}
|
package/agents/generic/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import messageQueue from './message-queue.js'
|
|
|
4
4
|
import stateImplementation from './state.js'
|
|
5
5
|
import watchImplementation from '../watch.js'
|
|
6
6
|
import downloadImplementation from '../download.js'
|
|
7
|
+
import sync from '../sync.js'
|
|
7
8
|
|
|
8
9
|
// TODO: consider using something better than name as mechanism
|
|
9
10
|
// for resoling default scope in context
|
|
@@ -229,6 +230,7 @@ export default function Agent({ Connection, domain, token, sid, uuid, fetch, app
|
|
|
229
230
|
debug,
|
|
230
231
|
guarantee,
|
|
231
232
|
response,
|
|
233
|
+
sync,
|
|
232
234
|
on
|
|
233
235
|
}
|
|
234
236
|
}
|
package/agents/generic/state.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { v4 as uuid, validate as isUUID } from 'uuid'
|
|
2
2
|
import PatchProxy from '@knowlearning/patch-proxy'
|
|
3
|
+
import attachSynced from '../attach-synced.js'
|
|
3
4
|
|
|
4
5
|
export default function(scope='[]', user, domain, { keyToSubscriptionId, watchers, states, create, environment, lastMessageResponse, lastInteractionResponse, interact, log }) {
|
|
5
6
|
let resolveMetadataPromise
|
|
6
7
|
let metadataPromise = new Promise(resolve => resolveMetadataPromise = resolve)
|
|
7
8
|
|
|
8
|
-
const statePromise = new Promise(async (resolveState, rejectState) => {
|
|
9
|
+
const statePromise = attachSynced(watchers, (ctx, resolveSync) => new Promise(async (resolveState, rejectState) => {
|
|
9
10
|
const { auth: { user: u }, domain: d, session } = await environment()
|
|
10
11
|
|
|
11
12
|
const qualifiedScope = isUUID(scope) ? scope : `${!domain || domain === d ? '' : domain}/${!user || user === u ? '' : user}/${scope}`
|
|
@@ -35,17 +36,20 @@ export default function(scope='[]', user, domain, { keyToSubscriptionId, watcher
|
|
|
35
36
|
const active = data.active
|
|
36
37
|
delete data.active
|
|
37
38
|
resolveMetadataPromise(data)
|
|
38
|
-
|
|
39
|
+
const proxy = new PatchProxy(active || {}, patch => {
|
|
40
|
+
if (ctx.applyingExternalUpdate) return
|
|
39
41
|
const activePatch = structuredClone(patch)
|
|
40
42
|
activePatch.forEach(entry => entry.path.unshift('active'))
|
|
41
43
|
interact(scope, activePatch)
|
|
42
|
-
})
|
|
44
|
+
})
|
|
45
|
+
resolveSync(proxy, qualifiedScope)
|
|
46
|
+
resolveState(proxy)
|
|
43
47
|
}
|
|
44
48
|
catch (error) {
|
|
45
49
|
rejectState(error)
|
|
46
50
|
}
|
|
47
|
-
})
|
|
51
|
+
}))
|
|
48
52
|
|
|
49
53
|
statePromise.metadata = metadataPromise
|
|
50
54
|
return statePromise
|
|
51
|
-
}
|
|
55
|
+
}
|
package/agents/sync.js
ADDED
package/package.json
CHANGED
package/types.d.ts
CHANGED
|
@@ -27,11 +27,16 @@ export interface AgentUploadInfo {
|
|
|
27
27
|
accept?: string;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
export interface SyncedStatePromise extends Promise<object> {
|
|
31
|
+
synced(callback?: (state: object, patch: object[]) => void): SyncedStatePromise;
|
|
32
|
+
metadata: Promise<object>;
|
|
33
|
+
}
|
|
34
|
+
|
|
30
35
|
export interface Agent {
|
|
31
36
|
login(provider: string): void;
|
|
32
37
|
logout(): void;
|
|
33
38
|
uuid(): string;
|
|
34
|
-
state(id: string, user?: string, domain?: string):
|
|
39
|
+
state(id: string, user?: string, domain?: string): SyncedStatePromise;
|
|
35
40
|
metadata(id: string, user?: string, domain?: string): Promise<object>;
|
|
36
41
|
watch(id: string, callback: (update: { state: object }) => void, user?: string, domain?: string): void;
|
|
37
42
|
upload(info?: AgentUploadInfo): Promise<string>;
|