solid-logic 1.3.17-615b75c1 → 1.3.17-6e0634d8
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/README.md +2 -2
- package/jest.config.js +1 -1
- package/lib/acl/aclLogic.d.ts +3 -30
- package/lib/acl/aclLogic.d.ts.map +1 -1
- package/lib/acl/aclLogic.js +150 -119
- package/lib/acl/aclLogic.js.map +1 -1
- package/lib/authn/SolidAuthnLogic.d.ts.map +1 -1
- package/lib/authn/SolidAuthnLogic.js +2 -2
- package/lib/authn/SolidAuthnLogic.js.map +1 -1
- package/lib/chat/chatLogic.d.ts +3 -0
- package/lib/chat/chatLogic.d.ts.map +1 -0
- package/lib/chat/{ChatLogic.js → chatLogic.js} +82 -86
- package/lib/chat/chatLogic.js.map +1 -0
- package/lib/inbox/inboxLogic.d.ts +3 -0
- package/lib/inbox/inboxLogic.d.ts.map +1 -0
- package/lib/inbox/{InboxLogic.js → inboxLogic.js} +59 -64
- package/lib/inbox/inboxLogic.js.map +1 -0
- package/lib/index.d.ts +6 -11
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +5 -25
- package/lib/index.js.map +1 -1
- package/lib/issuer/issuerLogic.js +1 -1
- package/lib/issuer/issuerLogic.js.map +1 -1
- package/lib/logic/CustomError.d.ts +4 -0
- package/lib/logic/CustomError.d.ts.map +1 -1
- package/lib/logic/CustomError.js +17 -1
- package/lib/logic/CustomError.js.map +1 -1
- package/lib/logic/solidLogic.d.ts +6 -0
- package/lib/logic/solidLogic.d.ts.map +1 -0
- package/lib/logic/solidLogic.js +92 -0
- package/lib/logic/solidLogic.js.map +1 -0
- package/lib/logic/solidLogicSingleton.d.ts +1 -2
- package/lib/logic/solidLogicSingleton.d.ts.map +1 -1
- package/lib/logic/solidLogicSingleton.js +3 -3
- package/lib/logic/solidLogicSingleton.js.map +1 -1
- package/lib/profile/profileLogic.d.ts +3 -0
- package/lib/profile/profileLogic.d.ts.map +1 -0
- package/lib/profile/profileLogic.js +246 -0
- package/lib/profile/profileLogic.js.map +1 -0
- package/lib/typeIndex/typeIndexLogic.d.ts +2 -21
- package/lib/typeIndex/typeIndexLogic.d.ts.map +1 -1
- package/lib/typeIndex/typeIndexLogic.js +304 -296
- package/lib/typeIndex/typeIndexLogic.js.map +1 -1
- package/lib/types.d.ts +82 -1
- package/lib/types.d.ts.map +1 -1
- package/lib/util/containerLogic.d.ts +11 -0
- package/lib/util/containerLogic.d.ts.map +1 -0
- package/lib/{profile/ProfileLogic.js → util/containerLogic.js} +51 -44
- package/lib/util/containerLogic.js.map +1 -0
- package/lib/util/ns.d.ts +2 -0
- package/lib/util/ns.d.ts.map +1 -0
- package/lib/util/ns.js +34 -0
- package/lib/util/ns.js.map +1 -0
- package/lib/util/utilityLogic.d.ts +15 -0
- package/lib/util/utilityLogic.d.ts.map +1 -0
- package/lib/util/utilityLogic.js +274 -0
- package/lib/util/utilityLogic.js.map +1 -0
- package/lib/util/utils.d.ts +8 -0
- package/lib/util/utils.d.ts.map +1 -0
- package/lib/util/utils.js +48 -0
- package/lib/util/utils.js.map +1 -0
- package/package.json +5 -1
- package/src/acl/aclLogic.ts +136 -118
- package/src/authn/SolidAuthnLogic.ts +3 -2
- package/src/chat/chatLogic.ts +225 -0
- package/src/inbox/inboxLogic.ts +58 -0
- package/src/index.ts +11 -29
- package/src/issuer/issuerLogic.ts +1 -1
- package/src/logic/CustomError.ts +5 -1
- package/src/logic/solidLogic.ts +75 -0
- package/src/logic/solidLogicSingleton.ts +3 -3
- package/src/profile/profileLogic.ts +126 -0
- package/src/typeIndex/typeIndexLogic.ts +175 -182
- package/src/types.ts +83 -4
- package/src/util/containerLogic.ts +53 -0
- package/src/util/ns.ts +5 -0
- package/src/util/utilityLogic.ts +156 -0
- package/src/util/utils.ts +52 -0
- package/test/aclLogic.test.ts +13 -4
- package/test/chatLogic.test.ts +70 -71
- package/test/container.test.ts +57 -0
- package/test/helpers/dataSetup.ts +134 -0
- package/test/helpers/setup.ts +1 -0
- package/test/inboxLogic.test.ts +40 -38
- package/test/logic.test.ts +10 -9
- package/test/profileLogic.test.ts +246 -0
- package/test/typeIndexLogic.test.ts +487 -30
- package/test/utilityLogic.test.ts +172 -126
- package/test/utils.test.ts +32 -0
- package/lib/chat/ChatLogic.d.ts +0 -26
- package/lib/chat/ChatLogic.d.ts.map +0 -1
- package/lib/chat/ChatLogic.js.map +0 -1
- package/lib/chat/determineChatContainer.d.ts +0 -3
- package/lib/chat/determineChatContainer.d.ts.map +0 -1
- package/lib/chat/determineChatContainer.js +0 -12
- package/lib/chat/determineChatContainer.js.map +0 -1
- package/lib/discovery/discoveryLogic.d.ts +0 -40
- package/lib/discovery/discoveryLogic.d.ts.map +0 -1
- package/lib/discovery/discoveryLogic.js +0 -494
- package/lib/discovery/discoveryLogic.js.map +0 -1
- package/lib/inbox/InboxLogic.d.ts +0 -18
- package/lib/inbox/InboxLogic.d.ts.map +0 -1
- package/lib/inbox/InboxLogic.js.map +0 -1
- package/lib/logic/SolidLogic.d.ts +0 -48
- package/lib/logic/SolidLogic.d.ts.map +0 -1
- package/lib/logic/SolidLogic.js +0 -321
- package/lib/logic/SolidLogic.js.map +0 -1
- package/lib/profile/ProfileLogic.d.ts +0 -13
- package/lib/profile/ProfileLogic.d.ts.map +0 -1
- package/lib/profile/ProfileLogic.js.map +0 -1
- package/lib/util/UtilityLogic.d.ts +0 -33
- package/lib/util/UtilityLogic.d.ts.map +0 -1
- package/lib/util/UtilityLogic.js +0 -240
- package/lib/util/UtilityLogic.js.map +0 -1
- package/lib/util/uri.d.ts +0 -3
- package/lib/util/uri.d.ts.map +0 -1
- package/lib/util/uri.js +0 -9
- package/lib/util/uri.js.map +0 -1
- package/src/chat/ChatLogic.ts +0 -244
- package/src/chat/determineChatContainer.ts +0 -14
- package/src/discovery/discoveryLogic.ts +0 -311
- package/src/inbox/InboxLogic.ts +0 -66
- package/src/logic/SolidLogic.ts +0 -262
- package/src/profile/ProfileLogic.ts +0 -44
- package/src/util/UtilityLogic.ts +0 -161
- package/src/util/uri.ts +0 -5
- package/test/discoveryLogic.test.ts +0 -740
|
@@ -1,201 +1,194 @@
|
|
|
1
|
-
import { NamedNode, st, sym } from
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import { newThing } from "../util/
|
|
6
|
-
import { AuthenticationContext } from "../types"
|
|
7
|
-
import { solidLogicSingleton } from "../logic/solidLogicSingleton"
|
|
8
|
-
// import { ensureLoadedPreferences } from '../logic/logic'
|
|
9
|
-
import { loadPreferences, loadProfile } from '../discovery/discoveryLogic'
|
|
10
|
-
export const ns = solidNamespace($rdf)
|
|
11
|
-
|
|
12
|
-
const store = solidLogicSingleton.store
|
|
13
|
-
|
|
14
|
-
async function ensureLoadedPreferences (context:AuthenticationContext) {
|
|
15
|
-
if (!context.me) throw new Error('@@ ensureLoadedPreferences: no user specified')
|
|
16
|
-
context.publicProfile = await loadProfile(store, context.me)
|
|
17
|
-
context.preferencesFile = await loadPreferences(store, context.me)
|
|
18
|
-
return context
|
|
19
|
-
}
|
|
1
|
+
import { NamedNode, st, sym } from 'rdflib'
|
|
2
|
+
import { ScopedApp, TypeIndexLogic, TypeIndexScope } from '../types'
|
|
3
|
+
import * as debug from "../util/debug"
|
|
4
|
+
import { ns as namespace } from '../util/ns'
|
|
5
|
+
import { newThing, uniqueNodes } from "../util/utils"
|
|
20
6
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
* output: index.public, index.private
|
|
24
|
-
* @@ This is a very bizare function
|
|
25
|
-
* @see https://github.com/solidos/solid/blob/main/proposals/data-discovery.md#discoverability
|
|
26
|
-
*/
|
|
27
|
-
export async function loadIndex (
|
|
28
|
-
context: AuthenticationContext,
|
|
29
|
-
isPublic: boolean
|
|
30
|
-
): Promise<AuthenticationContext> {
|
|
31
|
-
const indexes = await solidLogicSingleton.loadIndexes(
|
|
32
|
-
context.me as NamedNode,
|
|
33
|
-
(isPublic ? context.publicProfile || null : null),
|
|
34
|
-
(isPublic ? null : context.preferencesFile || null),
|
|
35
|
-
// async (err: Error) => widgets.complain(context, err.message)
|
|
36
|
-
async (err: Error) => debug.error(err.message) as undefined
|
|
37
|
-
)
|
|
38
|
-
context.index = context.index || {}
|
|
39
|
-
context.index.private = indexes.private.concat(context.index.private || []) // otherwise concat will wrongly add 'undefined' as a private index
|
|
40
|
-
context.index.public = indexes.public.concat(context.index.public || []) // otherwise concat will wrongly add 'undefined' as a public index
|
|
41
|
-
return context
|
|
42
|
-
}
|
|
7
|
+
export function createTypeIndexLogic(store, authn, profileLogic, utilityLogic): TypeIndexLogic {
|
|
8
|
+
const ns = namespace
|
|
43
9
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
try {
|
|
51
|
-
const indexes = await solidLogicSingleton.loadIndexes(
|
|
52
|
-
context.me as NamedNode,
|
|
53
|
-
context.publicProfile || null,
|
|
54
|
-
context.preferencesFile || null,
|
|
55
|
-
// async (err: Error) => widgets.complain(context, err.message)
|
|
56
|
-
// async (err: Error) => debug.warn(err.message) as undefined
|
|
57
|
-
)
|
|
58
|
-
context.index = context.index || {}
|
|
59
|
-
context.index.private = indexes.private || context.index.private
|
|
60
|
-
context.index.public = indexes.public || context.index.public
|
|
61
|
-
return context
|
|
62
|
-
} catch (error) {
|
|
63
|
-
async (error: Error) => debug.warn(error.message) as undefined
|
|
10
|
+
function getRegistrations(instance, theClass) {
|
|
11
|
+
return store
|
|
12
|
+
.each(undefined, ns.solid("instance"), instance)
|
|
13
|
+
.filter((r) => {
|
|
14
|
+
return store.holds(r, ns.solid("forClass"), theClass);
|
|
15
|
+
});
|
|
64
16
|
}
|
|
65
|
-
}
|
|
66
17
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
*/
|
|
71
|
-
export async function ensureTypeIndexes (context: AuthenticationContext, agent?: NamedNode): Promise<AuthenticationContext> {
|
|
72
|
-
if (!context.me) {
|
|
73
|
-
throw new Error(`ensureTypeIndexes: @@ no user`)
|
|
74
|
-
}
|
|
75
|
-
await ensureOneTypeIndex(context, true, agent)
|
|
76
|
-
await ensureOneTypeIndex(context, false, agent)
|
|
77
|
-
return context
|
|
78
|
-
}
|
|
18
|
+
async function loadTypeIndexesFor(user: NamedNode): Promise<Array<TypeIndexScope>> {
|
|
19
|
+
if (!user) throw new Error(`loadTypeIndexesFor: No user given`)
|
|
20
|
+
const profile = await profileLogic.loadProfile(user)
|
|
79
21
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
async function makeIndexIfNecessary (context, isPublic) {
|
|
90
|
-
const relevant = isPublic ? context.publicProfile : context.preferencesFile
|
|
91
|
-
if (!relevant) alert ('@@@@ relevent null')
|
|
92
|
-
const visibility = isPublic ? 'public' : 'private'
|
|
93
|
-
|
|
94
|
-
async function putIndex (newIndex) {
|
|
95
|
-
try {
|
|
96
|
-
await solidLogicSingleton.createEmptyRdfDoc(newIndex, 'Blank initial Type index')
|
|
97
|
-
return context
|
|
98
|
-
} catch (e) {
|
|
99
|
-
const msg = `Error creating new index ${e}`
|
|
100
|
-
// widgets.complain(context, msg)
|
|
101
|
-
debug.warn(msg)
|
|
102
|
-
}
|
|
103
|
-
} // putIndex
|
|
22
|
+
const suggestion = suggestPublicTypeIndex(user)
|
|
23
|
+
let publicTypeIndex
|
|
24
|
+
try {
|
|
25
|
+
publicTypeIndex = await utilityLogic.followOrCreateLink(user, ns.solid('publicTypeIndex') as NamedNode, suggestion, profile)
|
|
26
|
+
} catch (err) {
|
|
27
|
+
const message = `User ${user} has no pointer in profile to publicTypeIndex file.`
|
|
28
|
+
debug.warn(message)
|
|
29
|
+
}
|
|
30
|
+
const publicScopes = publicTypeIndex ? [{ label: 'public', index: publicTypeIndex as NamedNode, agent: user }] : []
|
|
104
31
|
|
|
32
|
+
let preferencesFile
|
|
33
|
+
try {
|
|
34
|
+
preferencesFile = await profileLogic.silencedLoadPreferences(user)
|
|
35
|
+
} catch (err) {
|
|
36
|
+
preferencesFile = null
|
|
37
|
+
}
|
|
105
38
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return
|
|
113
|
-
}
|
|
114
|
-
newIndex = sym(`${relevant.dir().uri + visibility}TypeIndex.ttl`)
|
|
115
|
-
debug.log(`Linking to new fresh type index ${newIndex}`)
|
|
116
|
-
if (!confirm(`OK to create a new empty index file at ${newIndex}, overwriting anything that is now there?`)) {
|
|
117
|
-
throw new Error('cancelled by user')
|
|
118
|
-
}
|
|
119
|
-
debug.log(`Linking to new fresh type index ${newIndex}`)
|
|
120
|
-
const addMe = [
|
|
121
|
-
st(context.me, ns.solid(`${visibility}TypeIndex`), newIndex, relevant)
|
|
122
|
-
]
|
|
39
|
+
let privateScopes
|
|
40
|
+
if (preferencesFile) { // watch out - can be in either as spec was not clear. Legacy is profile.
|
|
41
|
+
// If there is a legacy one linked from the profile, use that.
|
|
42
|
+
// Otherwiae use or make one linked from Preferences
|
|
43
|
+
const suggestedPrivateTypeIndex = suggestPrivateTypeIndex(preferencesFile)
|
|
44
|
+
let privateTypeIndex
|
|
123
45
|
try {
|
|
124
|
-
|
|
46
|
+
privateTypeIndex = store.any(user, ns.solid('privateTypeIndex'), undefined, profile) ||
|
|
47
|
+
await utilityLogic.followOrCreateLink(user, ns.solid('privateTypeIndex') as NamedNode, suggestedPrivateTypeIndex, preferencesFile);
|
|
125
48
|
} catch (err) {
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
debug.warn(msg)
|
|
129
|
-
return context
|
|
49
|
+
const message = `User ${user} has no pointer in preference file to privateTypeIndex file.`
|
|
50
|
+
debug.warn(message)
|
|
130
51
|
}
|
|
131
|
-
|
|
132
|
-
debug.log(`Creating new fresh type index file${newIndex}`)
|
|
133
|
-
await putIndex(newIndex)
|
|
134
|
-
context.index[visibility].push(newIndex) // @@ wait
|
|
52
|
+
privateScopes = privateTypeIndex ? [{ label: 'private', index: privateTypeIndex as NamedNode, agent: user }] : []
|
|
135
53
|
} else {
|
|
136
|
-
|
|
137
|
-
const ixs = context.index[visibility]
|
|
138
|
-
try {
|
|
139
|
-
await solidLogicSingleton.load(ixs)
|
|
140
|
-
} catch (err) {
|
|
141
|
-
const msg = `ensureOneTypeIndex: loading indexes ${err}`
|
|
142
|
-
debug.warn(msg)
|
|
143
|
-
// widgets.complain(context, `ensureOneTypeIndex: loading indexes ${err}`)
|
|
144
|
-
}
|
|
54
|
+
privateScopes = []
|
|
145
55
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
try {
|
|
154
|
-
await loadIndex(context2, isPublic)
|
|
155
|
-
const pp = isPublic ? 'public' : 'private'
|
|
156
|
-
if (context2.index && context2.index[pp]&& context2.index[pp].length > 0) {
|
|
157
|
-
debug.log(`ensureOneTypeIndex: Type index exists already ${context2.index[pp]}`)
|
|
158
|
-
return context2
|
|
56
|
+
const scopes = publicScopes.concat(privateScopes)
|
|
57
|
+
if (scopes.length === 0) return scopes
|
|
58
|
+
const files = scopes.map(scope => scope.index)
|
|
59
|
+
try {
|
|
60
|
+
await store.fetcher.load(files)
|
|
61
|
+
} catch (err) {
|
|
62
|
+
debug.warn('Problems loading type index: ', err)
|
|
159
63
|
}
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
|
|
64
|
+
return scopes
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function loadCommunityTypeIndexes(user: NamedNode): Promise<TypeIndexScope[][]> {
|
|
68
|
+
let preferencesFile
|
|
69
|
+
try {
|
|
70
|
+
preferencesFile = await profileLogic.silencedLoadPreferences(user)
|
|
71
|
+
} catch (err) {
|
|
72
|
+
const message = `User ${user} has no pointer in profile to preferences file.`
|
|
73
|
+
debug.warn(message)
|
|
74
|
+
}
|
|
75
|
+
if (preferencesFile) { // For now, pick up communities as simple links from the preferences file.
|
|
76
|
+
const communities = store.each(user, ns.solid('community'), undefined, preferencesFile as NamedNode).concat(
|
|
77
|
+
store.each(user, ns.solid('community'), undefined, user.doc() as NamedNode)
|
|
78
|
+
)
|
|
79
|
+
let result = []
|
|
80
|
+
for (const org of communities) {
|
|
81
|
+
result = result.concat(await loadTypeIndexesFor(org as NamedNode) as any)
|
|
82
|
+
}
|
|
83
|
+
return result
|
|
84
|
+
}
|
|
85
|
+
return [] // No communities
|
|
164
86
|
}
|
|
165
|
-
}
|
|
166
87
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
* used in chat in bookmark.js (solid-ui)
|
|
170
|
-
*/
|
|
171
|
-
export async function registerInTypeIndex (
|
|
172
|
-
context: AuthenticationContext,
|
|
173
|
-
instance: NamedNode,
|
|
174
|
-
theClass: NamedNode,
|
|
175
|
-
isPublic: boolean,
|
|
176
|
-
agent?: NamedNode // Defaults to current user
|
|
177
|
-
): Promise<AuthenticationContext> {
|
|
178
|
-
await ensureOneTypeIndex(context, isPublic, agent)
|
|
179
|
-
if (!context.index) {
|
|
180
|
-
throw new Error('registerInTypeIndex: No type index found')
|
|
88
|
+
async function loadAllTypeIndexes(user: NamedNode) {
|
|
89
|
+
return (await loadTypeIndexesFor(user)).concat((await loadCommunityTypeIndexes(user)).flat())
|
|
181
90
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
91
|
+
|
|
92
|
+
async function getScopedAppInstances(klass: NamedNode, user: NamedNode): Promise<ScopedApp[]> {
|
|
93
|
+
const scopes = await loadAllTypeIndexes(user)
|
|
94
|
+
let scopedApps = []
|
|
95
|
+
for (const scope of scopes) {
|
|
96
|
+
const scopedApps0 = await getScopedAppsFromIndex(scope, klass) as any
|
|
97
|
+
scopedApps = scopedApps.concat(scopedApps0)
|
|
98
|
+
}
|
|
99
|
+
return scopedApps
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// This is the function signature which used to be in solid-ui/logic
|
|
103
|
+
// Recommended to use getScopedAppInstances instead as it provides more information.
|
|
104
|
+
//
|
|
105
|
+
async function getAppInstances(klass: NamedNode): Promise<NamedNode[]> {
|
|
106
|
+
const user = authn.currentUser()
|
|
107
|
+
if (!user) throw new Error('getAppInstances: Must be logged in to find apps.')
|
|
108
|
+
const scopedAppInstances = await getScopedAppInstances(klass, user)
|
|
109
|
+
return scopedAppInstances.map(scoped => scoped.instance)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function suggestPublicTypeIndex(me: NamedNode) {
|
|
113
|
+
return sym(me.doc().dir()?.uri + 'publicTypeIndex.ttl')
|
|
114
|
+
}
|
|
115
|
+
// Note this one is based off the pref file not the profile
|
|
116
|
+
|
|
117
|
+
function suggestPrivateTypeIndex(preferencesFile: NamedNode) {
|
|
118
|
+
return sym(preferencesFile.doc().dir()?.uri + 'privateTypeIndex.ttl')
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/*
|
|
122
|
+
* Register a new app in a type index
|
|
123
|
+
* used in chat in bookmark.js (solid-ui)
|
|
124
|
+
* Returns the registration object if successful else null
|
|
125
|
+
*/
|
|
126
|
+
async function registerInTypeIndex(
|
|
127
|
+
instance: NamedNode,
|
|
128
|
+
index: NamedNode,
|
|
129
|
+
theClass: NamedNode,
|
|
130
|
+
// agent: NamedNode
|
|
131
|
+
): Promise<NamedNode | null> {
|
|
132
|
+
const registration = newThing(index)
|
|
133
|
+
const ins = [
|
|
134
|
+
// See https://github.com/solid/solid/blob/main/proposals/data-discovery.md
|
|
135
|
+
st(registration, ns.rdf('type'), ns.solid('TypeRegistration'), index),
|
|
136
|
+
st(registration, ns.solid('forClass'), theClass, index),
|
|
137
|
+
st(registration, ns.solid('instance'), instance, index)
|
|
138
|
+
]
|
|
139
|
+
try {
|
|
140
|
+
await store.updater.update([], ins)
|
|
141
|
+
} catch (err) {
|
|
142
|
+
const msg = `Unable to register ${instance} in index ${index}: ${err}`
|
|
143
|
+
console.warn(msg)
|
|
144
|
+
return null
|
|
145
|
+
}
|
|
146
|
+
return registration
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function deleteTypeIndexRegistration(item) {
|
|
150
|
+
const reg = store.the(null, ns.solid('instance'), item.instance, item.scope.index) as NamedNode
|
|
151
|
+
if (!reg) throw new Error(`deleteTypeIndexRegistration: No registration found for ${item.instance}`)
|
|
152
|
+
const statements = store.statementsMatching(reg, null, null, item.scope.index)
|
|
153
|
+
await store.updater.update(statements, [])
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function getScopedAppsFromIndex(scope: TypeIndexScope, theClass: NamedNode | null): Promise<ScopedApp[]> {
|
|
157
|
+
const index = scope.index
|
|
158
|
+
const registrations = store.statementsMatching(null, ns.solid('instance'), null, index)
|
|
159
|
+
.concat(store.statementsMatching(null, ns.solid('instanceContainer'), null, index))
|
|
160
|
+
.map(st => st.subject)
|
|
161
|
+
const relevant = theClass ? registrations.filter(reg => store.any(reg, ns.solid('forClass'), null, index)?.sameTerm(theClass))
|
|
162
|
+
: registrations
|
|
163
|
+
const directInstances = relevant.map(reg => store.each(reg, ns.solid('instance'), null, index).map(one => sym(one.value))).flat()
|
|
164
|
+
let instances = uniqueNodes(directInstances)
|
|
165
|
+
|
|
166
|
+
const instanceContainers = relevant.map(
|
|
167
|
+
reg => store.each(reg, ns.solid('instanceContainer'), null, index).map(one => sym(one.value))).flat()
|
|
168
|
+
|
|
169
|
+
// instanceContainers may be deprocatable if no one has used them
|
|
170
|
+
const containers = uniqueNodes(instanceContainers)
|
|
171
|
+
if (containers.length > 0) { console.log('@@ getScopedAppsFromIndex containers ', containers) }
|
|
172
|
+
for (let i = 0; i < containers.length; i++) {
|
|
173
|
+
const cont = containers[i]
|
|
174
|
+
await store.fetcher.load(cont)
|
|
175
|
+
const contents = store.each(cont, ns.ldp('contains'), null, cont).map(one => sym(one.value))
|
|
176
|
+
instances = instances.concat(contents)
|
|
177
|
+
}
|
|
178
|
+
return instances.map(instance => { return { instance, scope } })
|
|
185
179
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
registerInTypeIndex,
|
|
183
|
+
getRegistrations,
|
|
184
|
+
loadTypeIndexesFor,
|
|
185
|
+
loadCommunityTypeIndexes,
|
|
186
|
+
loadAllTypeIndexes,
|
|
187
|
+
getScopedAppInstances,
|
|
188
|
+
getAppInstances,
|
|
189
|
+
suggestPublicTypeIndex,
|
|
190
|
+
suggestPrivateTypeIndex,
|
|
191
|
+
deleteTypeIndexRegistration,
|
|
192
|
+
getScopedAppsFromIndex
|
|
199
193
|
}
|
|
200
|
-
return context
|
|
201
194
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Session } from "@inrupt/solid-client-authn-browser"
|
|
2
|
-
import { NamedNode } from "rdflib"
|
|
2
|
+
import { LiveStore, NamedNode, Statement } from "rdflib"
|
|
3
3
|
|
|
4
4
|
export type AppDetails = {
|
|
5
5
|
noun: string
|
|
@@ -32,12 +32,91 @@ export interface SolidNamespace {
|
|
|
32
32
|
[key: string]: (term: string) => NamedNode
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
export type TypeIndexScope = { label: string, index: NamedNode, agent: NamedNode }
|
|
36
|
+
export type ScopedApp = { instance: NamedNode, scope: TypeIndexScope }
|
|
37
|
+
|
|
38
|
+
export interface NewPaneOptions {
|
|
36
39
|
me?: NamedNode;
|
|
37
40
|
newInstance?: NamedNode;
|
|
38
41
|
newBase: string;
|
|
39
42
|
}
|
|
40
43
|
|
|
41
|
-
interface CreatedPaneOptions {
|
|
44
|
+
export interface CreatedPaneOptions {
|
|
42
45
|
newInstance: NamedNode;
|
|
43
|
-
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface ChatLogic {
|
|
49
|
+
setAcl: (chatContainer: NamedNode, me: NamedNode, invitee: NamedNode) => Promise<void>,
|
|
50
|
+
addToPrivateTypeIndex: (chatThing, me) => void | Promise<void>,
|
|
51
|
+
findChat: (invitee: NamedNode) => Promise<Chat>,
|
|
52
|
+
createChatThing: (chatContainer: NamedNode, me: NamedNode) => Promise<NamedNode>,
|
|
53
|
+
mintNew: (newPaneOptions: NewPaneOptions) => Promise<CreatedPaneOptions>,
|
|
54
|
+
getChat: (invitee: NamedNode, boolean) => Promise<NamedNode | null>,
|
|
55
|
+
sendInvite: (invitee: NamedNode, chatThing: NamedNode) => void
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface Chat {
|
|
59
|
+
me: NamedNode,
|
|
60
|
+
chatContainer: NamedNode,
|
|
61
|
+
exists: boolean
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface ProfileLogic {
|
|
65
|
+
silencedLoadPreferences: (user: NamedNode) => Promise<NamedNode | undefined>,
|
|
66
|
+
loadPreferences: (user: NamedNode) => Promise<NamedNode>,
|
|
67
|
+
loadProfile: (user: NamedNode) => Promise<NamedNode>,
|
|
68
|
+
loadMe: () => Promise<NamedNode>,
|
|
69
|
+
getPodRoot: (user: NamedNode) => NamedNode,
|
|
70
|
+
getMainInbox: (user: NamedNode) => Promise<NamedNode>,
|
|
71
|
+
findStorage: (me: NamedNode) => Node | null
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface AclLogic {
|
|
75
|
+
findAclDocUrl: (url: NamedNode) => Promise<any>,
|
|
76
|
+
setACLUserPublic: (docURI: string, me: NamedNode,
|
|
77
|
+
options: {
|
|
78
|
+
defaultForNew?: boolean,
|
|
79
|
+
public?: []
|
|
80
|
+
}
|
|
81
|
+
) => Promise<NamedNode>,
|
|
82
|
+
genACLText: (docURI: string, me: NamedNode, aclURI: string,
|
|
83
|
+
options: {
|
|
84
|
+
defaultForNew?: boolean,
|
|
85
|
+
public?: []
|
|
86
|
+
}
|
|
87
|
+
) => string | undefined
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface InboxLogic {
|
|
91
|
+
createInboxFor: (peerWebId: string, nick: string) => Promise<string>,
|
|
92
|
+
getNewMessages: (user?: NamedNode) => Promise<NamedNode[]>,
|
|
93
|
+
markAsRead: (url: string, date: Date) => void
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface TypeIndexLogic {
|
|
97
|
+
getRegistrations: (instance, theClass) => Node[],
|
|
98
|
+
loadTypeIndexesFor: (user: NamedNode) => Promise<Array<TypeIndexScope>>,
|
|
99
|
+
loadCommunityTypeIndexes: (user: NamedNode) => Promise<TypeIndexScope[][]>,
|
|
100
|
+
loadAllTypeIndexes: (user: NamedNode) => Promise<Array<TypeIndexScope>>,
|
|
101
|
+
getScopedAppInstances: (klass: NamedNode, user: NamedNode) => Promise<ScopedApp[]>,
|
|
102
|
+
getAppInstances: (klass: NamedNode) => Promise<NamedNode[]>,
|
|
103
|
+
suggestPublicTypeIndex: (me: NamedNode) => NamedNode,
|
|
104
|
+
suggestPrivateTypeIndex: (preferencesFile: NamedNode) => NamedNode,
|
|
105
|
+
registerInTypeIndex: (instance: NamedNode, index: NamedNode, theClass: NamedNode) => Promise<NamedNode | null>,
|
|
106
|
+
deleteTypeIndexRegistration: (item: any) => Promise<void>
|
|
107
|
+
getScopedAppsFromIndex: (scope: TypeIndexScope, theClass: NamedNode | null) => Promise<ScopedApp[]>
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface SolidLogic {
|
|
111
|
+
store: LiveStore,
|
|
112
|
+
authn: AuthnLogic,
|
|
113
|
+
acl: AclLogic,
|
|
114
|
+
profile: ProfileLogic,
|
|
115
|
+
inbox: InboxLogic,
|
|
116
|
+
typeIndex: TypeIndexLogic,
|
|
117
|
+
chat: ChatLogic,
|
|
118
|
+
load: (doc: NamedNode | NamedNode[] | string) => void,
|
|
119
|
+
updatePromise: (del: Array<Statement>, ins: Array<Statement>) => Promise<void>,
|
|
120
|
+
clearStore: () => void
|
|
121
|
+
}
|
|
122
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { NamedNode, Statement, sym } from "rdflib";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Container-related class
|
|
5
|
+
*/
|
|
6
|
+
export function createContainerLogic(store) {
|
|
7
|
+
|
|
8
|
+
function getContainerElements(containerNode: NamedNode): NamedNode[] {
|
|
9
|
+
return store
|
|
10
|
+
.statementsMatching(
|
|
11
|
+
containerNode,
|
|
12
|
+
sym("http://www.w3.org/ns/ldp#contains"),
|
|
13
|
+
undefined
|
|
14
|
+
)
|
|
15
|
+
.map((st: Statement) => st.object as NamedNode);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function isContainer(url: NamedNode) {
|
|
19
|
+
const nodeToString = url.value;
|
|
20
|
+
return nodeToString.charAt(nodeToString.length - 1) === "/";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function createContainer(url: string) {
|
|
24
|
+
const stringToNode = sym(url);
|
|
25
|
+
if (!isContainer(stringToNode)) {
|
|
26
|
+
throw new Error(`Not a container URL ${url}`);
|
|
27
|
+
}
|
|
28
|
+
// Copied from https://github.com/solidos/solid-crud-tests/blob/v3.1.0/test/surface/create-container.test.ts#L56-L64
|
|
29
|
+
const result = await store.fetcher._fetch(url, {
|
|
30
|
+
method: "PUT",
|
|
31
|
+
headers: {
|
|
32
|
+
"Content-Type": "text/turtle",
|
|
33
|
+
"If-None-Match": "*",
|
|
34
|
+
Link: '<http://www.w3.org/ns/ldp#BasicContainer>; rel="type"', // See https://github.com/solidos/node-solid-server/issues/1465
|
|
35
|
+
},
|
|
36
|
+
body: " ", // work around https://github.com/michielbdejong/community-server/issues/4#issuecomment-776222863
|
|
37
|
+
});
|
|
38
|
+
if (result.status.toString()[0] !== '2') {
|
|
39
|
+
throw new Error(`Not OK: got ${result.status} response while creating container at ${url}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function getContainerMembers(containerUrl: NamedNode): Promise<NamedNode[]> {
|
|
44
|
+
await store.fetcher.load(containerUrl);
|
|
45
|
+
return getContainerElements(containerUrl);
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
isContainer,
|
|
49
|
+
createContainer,
|
|
50
|
+
getContainerElements,
|
|
51
|
+
getContainerMembers
|
|
52
|
+
}
|
|
53
|
+
}
|
package/src/util/ns.ts
ADDED