solid-logic 1.3.17-8a332867 → 1.3.17-d95df8aa
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/jest.config.js +1 -1
- package/lib/discovery/discoveryLogic.d.ts +6 -9
- package/lib/discovery/discoveryLogic.d.ts.map +1 -1
- package/lib/discovery/discoveryLogic.js +92 -84
- package/lib/discovery/discoveryLogic.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/package.json +3 -1
- package/src/discovery/discoveryLogic.ts +40 -81
- package/src/index.ts +1 -0
- package/test/discoveryLogic.test.ts +503 -531
- package/test/helpers/setup.ts +0 -3
|
@@ -1,58 +1,40 @@
|
|
|
1
|
-
import { NamedNode,
|
|
2
|
-
|
|
3
|
-
// import { getContainerMembers } from '../util/UtilityLogic'
|
|
1
|
+
import { NamedNode, LiveStore, sym, st } from 'rdflib'
|
|
2
|
+
import * as $rdf from 'rdflib'
|
|
4
3
|
import { solidLogicSingleton } from "../logic/solidLogicSingleton"
|
|
5
4
|
import { newThing } from "../util/uri"
|
|
6
|
-
|
|
5
|
+
import solidNamespace from 'solid-namespace'
|
|
6
|
+
|
|
7
|
+
const { authn } = solidLogicSingleton
|
|
7
8
|
const { currentUser } = authn
|
|
9
|
+
const ns = solidNamespace($rdf)
|
|
8
10
|
|
|
9
|
-
type TypeIndexScope = { label: string, index: NamedNode, agent: NamedNode }
|
|
11
|
+
type TypeIndexScope = { label: string, index: NamedNode, agent: NamedNode }
|
|
10
12
|
type ScopedApp = { instance: NamedNode, scope: TypeIndexScope }
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
meeting: Namespace('http://www.w3.org/ns/pim/meeting#'),
|
|
16
|
-
rdf: Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#'),
|
|
17
|
-
schema: Namespace('http://schema.org/'),
|
|
18
|
-
solid: Namespace('http://www.w3.org/ns/solid/terms#'),
|
|
19
|
-
space: Namespace('http://www.w3.org/ns/pim/space#'),
|
|
20
|
-
stat: Namespace('http://www.w3.org/ns/posix/stat#'),
|
|
21
|
-
vcard: Namespace('http://www.w3.org/2006/vcard/ns#'),
|
|
22
|
-
wf: Namespace('http://www.w3.org/2005/01/wf/flow#'),
|
|
23
|
-
xsd: Namespace('http://www.w3.org/2001/XMLSchema#')
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** Create a resource if it really does not exist
|
|
28
|
-
* Be absolutely sure something does not exist before creating a new empty file
|
|
14
|
+
/**
|
|
15
|
+
* Create a resource if it really does not exist
|
|
16
|
+
* Be absolutely sure something does not exist before creating a new empty file
|
|
29
17
|
* as otherwise existing could be deleted.
|
|
30
18
|
* @param doc {NamedNode} - The resource
|
|
31
19
|
*/
|
|
32
20
|
export async function loadOrCreateIfNotExists (store: LiveStore, doc: NamedNode) {
|
|
33
21
|
let response
|
|
34
|
-
// console.log('@@ loadOrCreateIfNotExists doc ', doc)
|
|
35
22
|
try {
|
|
36
23
|
response = await store.fetcher.load(doc)
|
|
37
24
|
} catch (err) {
|
|
38
25
|
if (err.response.status === 404) {
|
|
39
|
-
// console.log('createIfNotExists doc does NOT exist, will create: ' + doc)
|
|
40
26
|
try {
|
|
41
27
|
store.fetcher.webOperation('PUT', doc, {data: '', contentType: 'text/turtle'})
|
|
42
28
|
} catch (err) {
|
|
43
29
|
const msg = 'createIfNotExists: PUT FAILED: ' + doc + ': ' + err
|
|
44
|
-
// console.log(msg)
|
|
45
30
|
throw new Error(msg)
|
|
46
31
|
}
|
|
47
32
|
delete store.fetcher.requested[doc.uri] // delete cached 404 error
|
|
48
|
-
// console.log('createIfNotExists doc created ok ' + doc)
|
|
49
33
|
} else {
|
|
50
34
|
const msg = 'createIfNotExists doc load error NOT 404: ' + doc + ': ' + err
|
|
51
|
-
// console.log(msg)
|
|
52
35
|
throw new Error(msg) // @@ add nested errors
|
|
53
36
|
}
|
|
54
37
|
}
|
|
55
|
-
// console.log('createIfNotExists doc exists, all good ' + doc)
|
|
56
38
|
return response
|
|
57
39
|
}
|
|
58
40
|
|
|
@@ -72,20 +54,18 @@ export function suggestPublicTypeIndex (me:NamedNode) {
|
|
|
72
54
|
export function suggestPrivateTypeIndex (preferencesFile:NamedNode) {
|
|
73
55
|
return sym(preferencesFile.doc().dir()?.uri + 'privateTypeIndex.ttl')
|
|
74
56
|
}
|
|
57
|
+
|
|
75
58
|
/* Follow link from this doc to another thing, or else make a new link
|
|
76
59
|
**
|
|
77
|
-
**
|
|
60
|
+
** return: null no ld one and failed to make a new one
|
|
78
61
|
*/
|
|
79
62
|
export async function followOrCreateLink (store: LiveStore, subject: NamedNode, predicate: NamedNode,
|
|
80
63
|
object: NamedNode, doc:NamedNode):Promise<NamedNode | null> {
|
|
81
64
|
await store.fetcher.load(doc)
|
|
82
65
|
const result = store.any(subject, predicate, null, doc)
|
|
83
|
-
// console.log('@@ followOrCreateLink result ', result)
|
|
84
66
|
|
|
85
67
|
if (result) return result as NamedNode
|
|
86
68
|
if (!store.updater.editable(doc)) {
|
|
87
|
-
// console.log(`followOrCreateLink: Can't modify ${doc} so can't make new link to ${object}.`)
|
|
88
|
-
// console.log('followOrCreateLink @@ connectedStatements', store.connectedStatements(subject))
|
|
89
69
|
return null
|
|
90
70
|
}
|
|
91
71
|
try {
|
|
@@ -95,58 +75,48 @@ export async function followOrCreateLink (store: LiveStore, subject: NamedNode,
|
|
|
95
75
|
return null
|
|
96
76
|
}
|
|
97
77
|
|
|
98
|
-
// console.log(`Success making link in ${doc} to ${object}` )
|
|
99
|
-
|
|
100
78
|
try {
|
|
101
79
|
await loadOrCreateIfNotExists(store, object)
|
|
102
80
|
// store.fetcher.webOperation('PUT', object, { data: '', contentType: 'text/turtle'})
|
|
103
81
|
} catch (err) {
|
|
104
82
|
console.warn(`followOrCreateLink: Error loading or saving new linked document: ${object}: ${err}`)
|
|
105
83
|
}
|
|
106
|
-
// console.log(`followOrCreateLink: Success loading or saving new linked document: ${object}.`)
|
|
107
84
|
return object
|
|
108
85
|
}
|
|
109
86
|
|
|
110
87
|
export async function loadProfile (store: LiveStore, user: NamedNode) {
|
|
111
|
-
// console.log(' @@ loadProfile: user', user)
|
|
112
88
|
if (!user) {
|
|
113
89
|
throw new Error(`loadProfile: no user given.`)
|
|
114
90
|
}
|
|
115
|
-
|
|
91
|
+
try {
|
|
116
92
|
await store.fetcher.load(user.doc())
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
93
|
+
} catch (err) {
|
|
94
|
+
throw new Error(`Unable to load profile of user ${user}: ${err}`)
|
|
95
|
+
}
|
|
120
96
|
return user.doc()
|
|
121
97
|
}
|
|
122
98
|
|
|
123
99
|
export async function loadPreferences (store: LiveStore, user: NamedNode): Promise <NamedNode | undefined > {
|
|
124
|
-
// console.log('loadPreferences @@ user', user)
|
|
125
100
|
await loadProfile(store as LiveStore, user)
|
|
126
101
|
|
|
127
102
|
const possiblePreferencesFile = suggestPreferencesFile(user)
|
|
128
103
|
|
|
129
104
|
const preferencesFile = await followOrCreateLink(store, user, ns.space('preferencesFile') as NamedNode, possiblePreferencesFile, user.doc())
|
|
130
|
-
// const preferencesFile = store.any(user, ns.space('preferencesFile'), undefined, profile)
|
|
131
105
|
|
|
132
|
-
// console.log('loadPreferences @@ pref file', preferencesFile)
|
|
133
106
|
if (!preferencesFile) {
|
|
134
107
|
const message = `User ${user} has no pointer in profile to preferences file.`
|
|
135
108
|
console.warn(message)
|
|
136
|
-
// throw new Error()
|
|
137
109
|
return undefined
|
|
138
110
|
}
|
|
139
111
|
try {
|
|
140
112
|
await store.fetcher.load(preferencesFile as NamedNode)
|
|
141
|
-
} catch (err) { //
|
|
113
|
+
} catch (err) { // Maybe a permission propblem or origin problem
|
|
142
114
|
return undefined
|
|
143
|
-
// throw new Error(`Unable to load preferences file ${preferencesFile} of user <${user}>: ${err}`)
|
|
144
115
|
}
|
|
145
116
|
return preferencesFile as NamedNode
|
|
146
117
|
}
|
|
147
118
|
|
|
148
119
|
export async function loadTypeIndexesFor (store: LiveStore, user:NamedNode): Promise<Array<TypeIndexScope>> {
|
|
149
|
-
// console.log('@@ loadTypeIndexesFor user', user)
|
|
150
120
|
if (!user) throw new Error(`loadTypeIndexesFor: No user given`)
|
|
151
121
|
const profile = await loadProfile(store, user)
|
|
152
122
|
|
|
@@ -154,9 +124,6 @@ export async function loadTypeIndexesFor (store: LiveStore, user:NamedNode): Pro
|
|
|
154
124
|
|
|
155
125
|
const publicTypeIndex = await followOrCreateLink(store, user, ns.solid('publicTypeIndex') as NamedNode, suggestion, profile)
|
|
156
126
|
|
|
157
|
-
// const publicTypeIndex = store.any(user, ns.solid('publicTypeIndex'), undefined, profile)
|
|
158
|
-
// console.log('@@ loadTypeIndexesFor publicTypeIndex', publicTypeIndex)
|
|
159
|
-
|
|
160
127
|
const publicScopes = publicTypeIndex ? [ { label: 'public', index: publicTypeIndex as NamedNode, agent: user } ] : []
|
|
161
128
|
|
|
162
129
|
let preferencesFile
|
|
@@ -174,7 +141,7 @@ export async function loadTypeIndexesFor (store: LiveStore, user:NamedNode): Pro
|
|
|
174
141
|
|
|
175
142
|
const privateTypeIndex = store.any(user, ns.solid('privateTypeIndex'), undefined, profile) ||
|
|
176
143
|
|
|
177
|
-
|
|
144
|
+
await followOrCreateLink(store, user, ns.solid('privateTypeIndex') as NamedNode, suggestedPrivateTypeIndex, preferencesFile);
|
|
178
145
|
|
|
179
146
|
privateScopes = privateTypeIndex ? [ { label: 'private', index: privateTypeIndex as NamedNode, agent: user } ] : []
|
|
180
147
|
} else {
|
|
@@ -183,7 +150,6 @@ export async function loadTypeIndexesFor (store: LiveStore, user:NamedNode): Pro
|
|
|
183
150
|
const scopes = publicScopes.concat(privateScopes)
|
|
184
151
|
if (scopes.length === 0) return scopes
|
|
185
152
|
const files = scopes.map(scope => scope.index)
|
|
186
|
-
// console.log('@@ loadTypeIndexesFor files ', files)
|
|
187
153
|
try {
|
|
188
154
|
await store.fetcher.load(files)
|
|
189
155
|
} catch (err) {
|
|
@@ -195,14 +161,13 @@ export async function loadTypeIndexesFor (store: LiveStore, user:NamedNode): Pro
|
|
|
195
161
|
export async function loadCommunityTypeIndexes (store:LiveStore, user:NamedNode): Promise<TypeIndexScope[][]> {
|
|
196
162
|
const preferencesFile = await loadPreferences(store, user)
|
|
197
163
|
if (preferencesFile) { // For now, pick up communities as simple links from the preferences file.
|
|
198
|
-
const communities = store.each(user, ns.solid('community'), undefined, preferencesFile as NamedNode)
|
|
199
|
-
|
|
164
|
+
const communities = store.each(user, ns.solid('community'), undefined, preferencesFile as NamedNode).concat(
|
|
165
|
+
store.each(user, ns.solid('community'), undefined, user.doc() as NamedNode)
|
|
166
|
+
)
|
|
200
167
|
let result = []
|
|
201
168
|
for (const org of communities) {
|
|
202
169
|
result = result.concat(await loadTypeIndexesFor(store, org as NamedNode) as any)
|
|
203
170
|
}
|
|
204
|
-
// const communityTypeIndexesPromises = communities.map(async community => await loadTypeIndexesFor(store, community as NamedNode))
|
|
205
|
-
// const result1 = Promise.all(communityTypeIndexesPromises)
|
|
206
171
|
return result
|
|
207
172
|
}
|
|
208
173
|
return [] // No communities
|
|
@@ -213,7 +178,6 @@ export async function loadAllTypeIndexes (store:LiveStore, user:NamedNode) {
|
|
|
213
178
|
}
|
|
214
179
|
|
|
215
180
|
// Utility: remove duplicates from Array of NamedNodes
|
|
216
|
-
|
|
217
181
|
export function uniqueNodes (arr: NamedNode[]): NamedNode[] {
|
|
218
182
|
const uris = arr.map(x => x.uri)
|
|
219
183
|
const set = new Set(uris)
|
|
@@ -222,45 +186,32 @@ export function uniqueNodes (arr: NamedNode[]): NamedNode[] {
|
|
|
222
186
|
return arr2 // Array.from(new Set(arr.map(x => x.uri))).map(u => sym(u))
|
|
223
187
|
}
|
|
224
188
|
|
|
225
|
-
export async function getScopedAppsFromIndex (store, scope, theClass: NamedNode) {
|
|
226
|
-
// console.log(`getScopedAppsFromIndex agent ${scope.agent} index: ${scope.index}` )
|
|
189
|
+
export async function getScopedAppsFromIndex (store, scope, theClass: NamedNode | null) {
|
|
227
190
|
const index = scope.index
|
|
228
|
-
const registrations = store.
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
const
|
|
232
|
-
|
|
191
|
+
const registrations = store.statementsMatching(null, ns.solid('instance'), null, index)
|
|
192
|
+
.concat(store.statementsMatching(null, ns.solid('instanceContainer'), null, index))
|
|
193
|
+
.map(st => st.subject)
|
|
194
|
+
const relevant = theClass ? registrations.filter(reg => store.any(reg, ns.solid('forClass'), null, index).sameTerm(theClass))
|
|
195
|
+
: registrations
|
|
196
|
+
const directInstances = relevant.map(reg => store.each(reg as NamedNode, ns.solid('instance'), null, index)).flat()
|
|
233
197
|
let instances = uniqueNodes(directInstances)
|
|
234
198
|
|
|
235
|
-
|
|
236
|
-
let instanceContainers = []
|
|
237
|
-
for (const reg of registrations) {
|
|
238
|
-
const cont = store.any(reg as NamedNode, ns.solid('instanceContainer'), null, index)
|
|
239
|
-
if (cont) {
|
|
240
|
-
// console.log(' @@ getScopedAppsFromIndex got one: ', cont)
|
|
241
|
-
instanceContainers.push(cont)
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
*/
|
|
245
|
-
const instanceContainers = registrations.map(
|
|
199
|
+
const instanceContainers = relevant.map(
|
|
246
200
|
reg => store.each(reg as NamedNode, ns.solid('instanceContainer'), null, index)).flat()
|
|
247
201
|
|
|
248
202
|
// instanceContainers may be deprocatable if no one has used them
|
|
249
|
-
|
|
250
203
|
const containers = uniqueNodes(instanceContainers)
|
|
204
|
+
if (containers.length > 0) { console.log('@@ getScopedAppsFromIndex containers ', containers)}
|
|
251
205
|
for (let i = 0; i < containers.length; i++) {
|
|
252
206
|
const cont = containers[i]
|
|
253
207
|
await store.fetcher.load(cont)
|
|
254
208
|
const contents = store.each(cont, ns.ldp('contains'), null, cont)
|
|
255
|
-
// if (contents.length) console.log('getScopedAppsFromIndex @@ instanceContainer contents:', contents)
|
|
256
209
|
instances = instances.concat(contents)
|
|
257
210
|
}
|
|
258
211
|
return instances.map(instance => { return {instance, scope}})
|
|
259
212
|
}
|
|
260
213
|
|
|
261
|
-
|
|
262
214
|
export async function getScopedAppInstances (store:LiveStore, klass: NamedNode, user: NamedNode):Promise<ScopedApp[]> {
|
|
263
|
-
// console.log('getScopedAppInstances @@ ' + user)
|
|
264
215
|
const scopes = await loadAllTypeIndexes(store, user)
|
|
265
216
|
let scopedApps = []
|
|
266
217
|
for (const scope of scopes) {
|
|
@@ -269,6 +220,7 @@ export async function getScopedAppInstances (store:LiveStore, klass: NamedNode,
|
|
|
269
220
|
}
|
|
270
221
|
return scopedApps
|
|
271
222
|
}
|
|
223
|
+
|
|
272
224
|
// This is the function signature which used to be in solid-ui/logic
|
|
273
225
|
// Recommended to use getScopedAppInstances instead as it provides more information.
|
|
274
226
|
//
|
|
@@ -278,7 +230,8 @@ export async function getAppInstances (store:LiveStore, klass: NamedNode): Promi
|
|
|
278
230
|
const scopedAppInstances = await getScopedAppInstances(store, klass, user)
|
|
279
231
|
return scopedAppInstances.map(scoped => scoped.instance)
|
|
280
232
|
}
|
|
281
|
-
|
|
233
|
+
|
|
234
|
+
/*
|
|
282
235
|
* Register a new app in a type index
|
|
283
236
|
* used in chat in bookmark.js (solid-ui)
|
|
284
237
|
* Returns the registration object if successful else null
|
|
@@ -298,7 +251,6 @@ export async function registerInstanceInTypeIndex (
|
|
|
298
251
|
st(registration, ns.solid('instance'), instance, index)
|
|
299
252
|
]
|
|
300
253
|
try {
|
|
301
|
-
console.log('patching index', ins)
|
|
302
254
|
await store.updater.update([], ins)
|
|
303
255
|
} catch (err) {
|
|
304
256
|
const msg = `Unable to register ${instance} in index ${index}: ${err}`
|
|
@@ -307,4 +259,11 @@ export async function registerInstanceInTypeIndex (
|
|
|
307
259
|
}
|
|
308
260
|
return registration
|
|
309
261
|
}
|
|
262
|
+
|
|
263
|
+
export async function deleteTypeIndexRegistration (store: LiveStore, item) {
|
|
264
|
+
const reg = store.the(null, ns.solid('instance'), item.instance, item.scope.index) as NamedNode
|
|
265
|
+
if (!reg) throw new Error(`deleteTypeIndexRegistration: No registration found for ${item.instance}`)
|
|
266
|
+
const statements = store.statementsMatching(reg, null, null, item.scope.index)
|
|
267
|
+
await store.updater.update(statements, [])
|
|
268
|
+
}
|
|
310
269
|
// ENDS
|
package/src/index.ts
CHANGED
|
@@ -23,6 +23,7 @@ export {
|
|
|
23
23
|
// Generate by
|
|
24
24
|
// grep export src/discovery/discoveryLogic.ts | sed -e 's/export //g' | sed -e 's/async //g'| sed -e 's/function //g' | sed -e 's/ .*/,/g' | sort
|
|
25
25
|
export {
|
|
26
|
+
deleteTypeIndexRegistration,
|
|
26
27
|
followOrCreateLink,
|
|
27
28
|
getAppInstances,
|
|
28
29
|
getScopedAppInstances,
|