solid-logic 1.3.17-7b06fb45 → 1.3.17-7b8c254b
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/lib/acl/aclLogic.d.ts +2 -11
- package/lib/acl/aclLogic.d.ts.map +1 -1
- package/lib/acl/aclLogic.js +8 -12
- package/lib/acl/aclLogic.js.map +1 -1
- package/lib/chat/chatLogic.d.ts +2 -15
- package/lib/chat/chatLogic.d.ts.map +1 -1
- package/lib/chat/chatLogic.js +8 -7
- package/lib/chat/chatLogic.js.map +1 -1
- package/lib/inbox/inboxLogic.d.ts +2 -6
- package/lib/inbox/inboxLogic.d.ts.map +1 -1
- package/lib/inbox/inboxLogic.js +3 -2
- package/lib/inbox/inboxLogic.js.map +1 -1
- package/lib/index.d.ts +4 -18
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -86
- package/lib/index.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 → solidLogic.js} +38 -33
- 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 +2 -2
- package/lib/logic/solidLogicSingleton.js.map +1 -1
- package/lib/profile/profileLogic.d.ts +2 -12
- package/lib/profile/profileLogic.d.ts.map +1 -1
- package/lib/profile/profileLogic.js +1 -23
- package/lib/profile/profileLogic.js.map +1 -1
- package/lib/typeIndex/typeIndexLogic.d.ts +2 -31
- package/lib/typeIndex/typeIndexLogic.d.ts.map +1 -1
- package/lib/typeIndex/typeIndexLogic.js +12 -359
- package/lib/typeIndex/typeIndexLogic.js.map +1 -1
- package/lib/types.d.ts +65 -1
- package/lib/types.d.ts.map +1 -1
- package/lib/util/containerLogic.d.ts +2 -2
- package/lib/util/containerLogic.d.ts.map +1 -1
- package/lib/util/containerLogic.js +8 -10
- package/lib/util/containerLogic.js.map +1 -1
- 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 +1 -1
- package/lib/util/utilityLogic.d.ts.map +1 -1
- package/lib/util/utilityLogic.js +9 -7
- package/lib/util/utilityLogic.js.map +1 -1
- package/package.json +3 -1
- package/src/acl/aclLogic.ts +11 -9
- package/src/chat/chatLogic.ts +7 -7
- package/src/inbox/inboxLogic.ts +6 -5
- package/src/index.ts +5 -147
- package/src/logic/solidLogic.ts +75 -0
- package/src/logic/solidLogicSingleton.ts +2 -2
- package/src/profile/profileLogic.ts +4 -12
- package/src/typeIndex/typeIndexLogic.ts +6 -277
- package/src/types.ts +76 -1
- package/src/util/containerLogic.ts +30 -31
- package/src/util/{ns.js → ns.ts} +0 -0
- package/src/util/utilityLogic.ts +8 -7
- package/test/container.test.ts +7 -6
- package/test/inboxLogic.test.ts +2 -1
- package/test/typeIndexLogic.test.ts +484 -54
- package/lib/logic/SolidLogic.d.ts +0 -22
- package/lib/logic/SolidLogic.d.ts.map +0 -1
- package/lib/logic/SolidLogic.js.map +0 -1
- package/lib/logic/solidLogicSingletonNew.d.ts +0 -80
- package/lib/logic/solidLogicSingletonNew.d.ts.map +0 -1
- package/lib/logic/solidLogicSingletonNew.js +0 -238
- package/lib/logic/solidLogicSingletonNew.js.map +0 -1
- package/src/logic/SolidLogic.ts +0 -81
- package/src/logic/solidLogicSingletonNew.ts +0 -239
- package/test/typeIndexLogicPart2.test.ts +0 -485
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Session } from "@inrupt/solid-client-authn-browser";
|
|
2
|
+
import * as rdf from "rdflib";
|
|
3
|
+
import { LiveStore, NamedNode, Statement } from "rdflib";
|
|
4
|
+
import { createAclLogic } from "../acl/aclLogic";
|
|
5
|
+
import { SolidAuthnLogic } from "../authn/SolidAuthnLogic";
|
|
6
|
+
import { createChatLogic } from "../chat/chatLogic";
|
|
7
|
+
import { createInboxLogic } from "../inbox/inboxLogic";
|
|
8
|
+
import { createProfileLogic } from "../profile/profileLogic";
|
|
9
|
+
import { createTypeIndexLogic } from "../typeIndex/typeIndexLogic";
|
|
10
|
+
import { createContainerLogic } from "../util/containerLogic";
|
|
11
|
+
import { createUtilityLogic } from "../util/utilityLogic";
|
|
12
|
+
import { AuthnLogic, SolidLogic } from "../types";
|
|
13
|
+
import * as debug from "../util/debug";
|
|
14
|
+
/*
|
|
15
|
+
** It is important to distinquish `fetch`, a function provided by the browser
|
|
16
|
+
** and `Fetcher`, a helper object for the rdflib Store which turns it
|
|
17
|
+
** into a `ConnectedStore` or a `LiveStore`. A Fetcher object is
|
|
18
|
+
** available at store.fetcher, and `fetch` function at `store.fetcher._fetch`,
|
|
19
|
+
*/
|
|
20
|
+
export function createSolidLogic(specialFetch: { fetch: (url: any, requestInit: any) => any }, session: Session): SolidLogic {
|
|
21
|
+
|
|
22
|
+
debug.log("SolidLogic: Unique instance created. There should only be one of these.")
|
|
23
|
+
const store: LiveStore = rdf.graph() as LiveStore
|
|
24
|
+
rdf.fetcher(store, {fetch: specialFetch.fetch}); // Attach a web I/O module, store.fetcher
|
|
25
|
+
store.updater = new rdf.UpdateManager(store); // Add real-time live updates store.updater
|
|
26
|
+
store.features = [] // disable automatic node merging on store load
|
|
27
|
+
|
|
28
|
+
const authn: AuthnLogic = new SolidAuthnLogic(session)
|
|
29
|
+
|
|
30
|
+
const acl = createAclLogic(store)
|
|
31
|
+
const containerLogic = createContainerLogic(store)
|
|
32
|
+
const utilityLogic = createUtilityLogic(store, acl, containerLogic)
|
|
33
|
+
const profile = createProfileLogic(store, authn, utilityLogic)
|
|
34
|
+
const chat = createChatLogic(store, profile)
|
|
35
|
+
const inbox = createInboxLogic(store, profile, utilityLogic, containerLogic, acl)
|
|
36
|
+
const typeIndex = createTypeIndexLogic(store, authn, profile, utilityLogic)
|
|
37
|
+
debug.log('SolidAuthnLogic initialized')
|
|
38
|
+
|
|
39
|
+
function load(doc: NamedNode | NamedNode[] | string) {
|
|
40
|
+
return store.fetcher.load(doc);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// @@@@ use the one in rdflib.js when it is available and delete this
|
|
44
|
+
function updatePromise(
|
|
45
|
+
del: Array<Statement>,
|
|
46
|
+
ins: Array<Statement> = []
|
|
47
|
+
): Promise<void> {
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
store.updater.update(del, ins, function (_uri, ok, errorBody) {
|
|
50
|
+
if (!ok) {
|
|
51
|
+
reject(new Error(errorBody));
|
|
52
|
+
} else {
|
|
53
|
+
resolve();
|
|
54
|
+
}
|
|
55
|
+
}); // callback
|
|
56
|
+
}); // promise
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function clearStore() {
|
|
60
|
+
store.statements.slice().forEach(store.remove.bind(store));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
store,
|
|
65
|
+
authn,
|
|
66
|
+
acl,
|
|
67
|
+
inbox,
|
|
68
|
+
chat,
|
|
69
|
+
profile,
|
|
70
|
+
typeIndex,
|
|
71
|
+
load,
|
|
72
|
+
updatePromise,
|
|
73
|
+
clearStore
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as debug from "../util/debug"
|
|
2
2
|
import { authSession } from "../authSession/authSession"
|
|
3
|
-
import {
|
|
3
|
+
import { createSolidLogic } from "./solidLogic"
|
|
4
4
|
|
|
5
5
|
const _fetch = async (url, requestInit) => {
|
|
6
6
|
const omitCreds = requestInit && requestInit.credentials && requestInit.credentials == 'omit'
|
|
@@ -13,7 +13,7 @@ const _fetch = async (url, requestInit) => {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
//this const makes solidLogicSingleton global accessible in mashlib
|
|
16
|
-
const solidLogicSingleton =
|
|
16
|
+
const solidLogicSingleton = createSolidLogic({ fetch: _fetch }, authSession)
|
|
17
17
|
|
|
18
18
|
debug.log('Unique quadstore initialized.')
|
|
19
19
|
|
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
import { NamedNode } from "rdflib";
|
|
2
2
|
import { CrossOriginForbiddenError, FetchError, NotEditableError, SameOriginForbiddenError, UnauthorizedError, WebOperationError } from "../logic/CustomError";
|
|
3
|
-
import { AuthenticationContext } from "../types";
|
|
4
3
|
import * as debug from "../util/debug";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { ns as namespace } from '../util/ns';
|
|
5
|
+
import { differentOrigin, suggestPreferencesFile } from "../util/utils"
|
|
6
|
+
import { ProfileLogic } from "../types"
|
|
7
7
|
|
|
8
|
-
export function createProfileLogic(store, authn, utilityLogic) {
|
|
8
|
+
export function createProfileLogic(store, authn, utilityLogic): ProfileLogic {
|
|
9
9
|
const ns = namespace
|
|
10
10
|
|
|
11
|
-
async function ensureLoadedPreferences (context: AuthenticationContext) {
|
|
12
|
-
if (!context.me) throw new Error('@@ ensureLoadedPreferences: no user specified')
|
|
13
|
-
context.publicProfile = await loadProfile(context.me)
|
|
14
|
-
context.preferencesFile = await silencedLoadPreferences(context.me)
|
|
15
|
-
return context
|
|
16
|
-
}
|
|
17
|
-
|
|
18
11
|
/**
|
|
19
12
|
* loads the preference without throwing errors - if it can create it it does so.
|
|
20
13
|
* remark: it still throws error if it cannot load profile.
|
|
@@ -121,7 +114,6 @@ export function createProfileLogic(store, authn, utilityLogic) {
|
|
|
121
114
|
}
|
|
122
115
|
|
|
123
116
|
return {
|
|
124
|
-
ensureLoadedPreferences,
|
|
125
117
|
loadMe,
|
|
126
118
|
getPodRoot,
|
|
127
119
|
getMainInbox,
|
|
@@ -1,273 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { AuthenticationContext, ScopedApp, TypeIndexScope } from '../types'
|
|
1
|
+
import { NamedNode, st, sym } from 'rdflib'
|
|
2
|
+
import { ScopedApp, TypeIndexLogic, TypeIndexScope } from '../types'
|
|
4
3
|
import * as debug from "../util/debug"
|
|
5
|
-
import {ns as namespace } from '../util/ns'
|
|
4
|
+
import { ns as namespace } from '../util/ns'
|
|
6
5
|
import { newThing, uniqueNodes } from "../util/utils"
|
|
7
6
|
|
|
8
|
-
export function createTypeIndexLogic(store, authn, profileLogic, utilityLogic) {
|
|
7
|
+
export function createTypeIndexLogic(store, authn, profileLogic, utilityLogic): TypeIndexLogic {
|
|
9
8
|
const ns = namespace
|
|
10
|
-
|
|
11
|
-
function updatePromise(
|
|
12
|
-
del: Array<Statement>,
|
|
13
|
-
ins: Array<Statement> = []
|
|
14
|
-
): Promise<void> {
|
|
15
|
-
return new Promise((resolve, reject) => {
|
|
16
|
-
store.updater.update(del, ins, function (_uri, ok, errorBody) {
|
|
17
|
-
if (!ok) {
|
|
18
|
-
reject(new Error(errorBody));
|
|
19
|
-
} else {
|
|
20
|
-
resolve();
|
|
21
|
-
}
|
|
22
|
-
}); // callback
|
|
23
|
-
}); // promise
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Resolves with the same context, outputting
|
|
27
|
-
* @see https://github.com/solidos/solid/blob/main/proposals/data-discovery.md#discoverability
|
|
28
|
-
*/
|
|
29
|
-
async function ensureTypeIndexes(context: AuthenticationContext, agent?: NamedNode): Promise<AuthenticationContext> {
|
|
30
|
-
if (!context.me) {
|
|
31
|
-
throw new Error(`ensureTypeIndexes: @@ no user`)
|
|
32
|
-
}
|
|
33
|
-
await ensureOneTypeIndex(context, true, agent)
|
|
34
|
-
await ensureOneTypeIndex(context, false, agent)
|
|
35
|
-
return context
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async function loadTypeIndexes(context: AuthenticationContext) {
|
|
39
|
-
try {
|
|
40
|
-
await profileLogic.silencedLoadPreferences(context.me as NamedNode)
|
|
41
|
-
} catch (error) {
|
|
42
|
-
debug.warn(error.message) as undefined
|
|
43
|
-
}
|
|
44
|
-
try {
|
|
45
|
-
const indexes = await loadIndexes(
|
|
46
|
-
context.me as NamedNode,
|
|
47
|
-
context.publicProfile || null,
|
|
48
|
-
context.preferencesFile || null,
|
|
49
|
-
// async (err: Error) => widgets.complain(context, err.message)
|
|
50
|
-
// async (err: Error) => debug.warn(err.message) as undefined
|
|
51
|
-
)
|
|
52
|
-
context.index = context.index || {}
|
|
53
|
-
context.index.private = indexes.private || context.index.private
|
|
54
|
-
context.index.public = indexes.public || context.index.public
|
|
55
|
-
return context
|
|
56
|
-
} catch (error) {
|
|
57
|
-
async (error: Error) => debug.warn(error.message) as undefined
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Register a new app in a type index
|
|
63
|
-
* used in chat in bookmark.js (solid-ui)
|
|
64
|
-
*/
|
|
65
|
-
async function registerInTypeIndex(
|
|
66
|
-
context: AuthenticationContext,
|
|
67
|
-
instance: NamedNode,
|
|
68
|
-
theClass: NamedNode,
|
|
69
|
-
isPublic: boolean,
|
|
70
|
-
agent?: NamedNode // Defaults to current user
|
|
71
|
-
): Promise<AuthenticationContext> {
|
|
72
|
-
await ensureOneTypeIndex(context, isPublic, agent)
|
|
73
|
-
if (!context.index) {
|
|
74
|
-
throw new Error('registerInTypeIndex: No type index found')
|
|
75
|
-
}
|
|
76
|
-
const indexes = isPublic ? context.index.public : context.index.private
|
|
77
|
-
if (!indexes.length) {
|
|
78
|
-
throw new Error('registerInTypeIndex: What no type index?')
|
|
79
|
-
}
|
|
80
|
-
const index = indexes[0]
|
|
81
|
-
const registration = newThing(index)
|
|
82
|
-
const ins = [
|
|
83
|
-
// See https://github.com/solidos/solid/blob/main/proposals/data-discovery.md
|
|
84
|
-
st(registration, ns.rdf('type'), ns.solid('TypeRegistration'), index),
|
|
85
|
-
st(registration, ns.solid('forClass'), theClass, index),
|
|
86
|
-
st(registration, ns.solid('instance'), instance, index)
|
|
87
|
-
]
|
|
88
|
-
try {
|
|
89
|
-
await updatePromise([], ins)
|
|
90
|
-
} catch (e) {
|
|
91
|
-
debug.log(e)
|
|
92
|
-
alert(e)
|
|
93
|
-
}
|
|
94
|
-
return context
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Resolves with the same context, outputting
|
|
99
|
-
* output: index.public, index.private
|
|
100
|
-
* @@ This is a very bizare function
|
|
101
|
-
* @see https://github.com/solidos/solid/blob/main/proposals/data-discovery.md#discoverability
|
|
102
|
-
*/
|
|
103
|
-
async function loadIndex(
|
|
104
|
-
context: AuthenticationContext,
|
|
105
|
-
isPublic: boolean
|
|
106
|
-
): Promise<AuthenticationContext> {
|
|
107
|
-
const indexes = await loadIndexes(
|
|
108
|
-
context.me as NamedNode,
|
|
109
|
-
(isPublic ? context.publicProfile || null : null),
|
|
110
|
-
(isPublic ? null : context.preferencesFile || null),
|
|
111
|
-
// async (err: Error) => widgets.complain(context, err.message)
|
|
112
|
-
async (err: Error) => debug.error(err.message) as undefined
|
|
113
|
-
)
|
|
114
|
-
context.index = context.index || {}
|
|
115
|
-
context.index.private = indexes.private.concat(context.index.private || []) // otherwise concat will wrongly add 'undefined' as a private index
|
|
116
|
-
context.index.public = indexes.public.concat(context.index.public || []) // otherwise concat will wrongly add 'undefined' as a public index
|
|
117
|
-
return context
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Load or create ONE type index
|
|
122
|
-
* Find one or make one or fail
|
|
123
|
-
* Many reasons for failing including script not having permission etc
|
|
124
|
-
*
|
|
125
|
-
* Adds its output to the context
|
|
126
|
-
* @see https://github.com/solidos/solid/blob/main/proposals/data-discovery.md#discoverability
|
|
127
|
-
*/
|
|
128
|
-
async function ensureOneTypeIndex(context: AuthenticationContext, isPublic: boolean, agent?: NamedNode): Promise<AuthenticationContext | void> {
|
|
129
|
-
|
|
130
|
-
const context2 = await profileLogic.ensureLoadedPreferences(context)
|
|
131
|
-
if (!context2.publicProfile) throw new Error(`@@ type index: no publicProfile`)
|
|
132
|
-
if (!context2.preferencesFile) throw new Error(`@@ type index: no preferencesFile for profile ${context2.publicProfile}`)
|
|
133
|
-
const relevant = isPublic ? context2.publicProfile : context2.preferencesFile
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
await loadIndex(context2, isPublic)
|
|
137
|
-
const pp = isPublic ? 'public' : 'private'
|
|
138
|
-
if (context2.index && context2.index[pp] && context2.index[pp].length > 0) {
|
|
139
|
-
debug.log(`ensureOneTypeIndex: Type index exists already ${context2.index[pp]}`)
|
|
140
|
-
return context2
|
|
141
|
-
}
|
|
142
|
-
await makeIndexIfNecessary(context2, isPublic, store, ns)
|
|
143
|
-
} catch (error) {
|
|
144
|
-
await makeIndexIfNecessary(context2, isPublic, store, ns)
|
|
145
|
-
// widgets.complain(context2, 'calling loadIndex:' + error)
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
async function putIndex(newIndex, context) {
|
|
150
|
-
try {
|
|
151
|
-
await utilityLogic.createEmptyRdfDoc(newIndex, 'Blank initial Type index')
|
|
152
|
-
return context
|
|
153
|
-
} catch (e) {
|
|
154
|
-
const msg = `Error creating new index ${e}`
|
|
155
|
-
// widgets.complain(context, msg)
|
|
156
|
-
debug.warn(msg)
|
|
157
|
-
}
|
|
158
|
-
} // putIndex
|
|
159
|
-
|
|
160
|
-
async function makeIndexIfNecessary(context, isPublic, store, ns) {
|
|
161
|
-
const relevant = isPublic ? context.publicProfile : context.preferencesFile
|
|
162
|
-
if (!relevant) alert('@@@@ relevent null')
|
|
163
|
-
const visibility = isPublic ? 'public' : 'private'
|
|
164
|
-
|
|
165
|
-
context.index = context.index || {}
|
|
166
|
-
context.index[visibility] = context.index[visibility] || []
|
|
167
|
-
let newIndex
|
|
168
|
-
if (context.index[visibility].length === 0) {
|
|
169
|
-
if (!store.updater.editable(relevant)) {
|
|
170
|
-
debug.log(`Not adding new type index as ${relevant} is not editable`)
|
|
171
|
-
return
|
|
172
|
-
}
|
|
173
|
-
newIndex = rdf.sym(`${relevant.dir().uri + visibility}TypeIndex.ttl`)
|
|
174
|
-
debug.log(`Linking to new fresh type index ${newIndex}`)
|
|
175
|
-
if (!confirm(`OK to create a new empty index file at ${newIndex}, overwriting anything that is now there?`)) {
|
|
176
|
-
throw new Error('cancelled by user')
|
|
177
|
-
}
|
|
178
|
-
debug.log(`Linking to new fresh type index ${newIndex}`)
|
|
179
|
-
const addMe = [
|
|
180
|
-
st(context.me, ns.solid(`${visibility}TypeIndex`), newIndex, relevant)
|
|
181
|
-
]
|
|
182
|
-
try {
|
|
183
|
-
await updatePromise([], addMe)
|
|
184
|
-
} catch (err) {
|
|
185
|
-
const msg = `Error saving type index link saving back ${newIndex}: ${err}`
|
|
186
|
-
//widgets.complain(context, msg)
|
|
187
|
-
debug.warn(msg)
|
|
188
|
-
return context
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
debug.log(`Creating new fresh type index file${newIndex}`)
|
|
192
|
-
await putIndex(newIndex, context)
|
|
193
|
-
context.index[visibility].push(newIndex) // @@ wait
|
|
194
|
-
} else {
|
|
195
|
-
// officially exists
|
|
196
|
-
const ixs = context.index[visibility]
|
|
197
|
-
try {
|
|
198
|
-
await store.fetcher.load(ixs)
|
|
199
|
-
} catch (err) {
|
|
200
|
-
const msg = `ensureOneTypeIndex: loading indexes ${err}`
|
|
201
|
-
debug.warn(msg)
|
|
202
|
-
// widgets.complain(context, `ensureOneTypeIndex: loading indexes ${err}`)
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
} // makeIndexIfNecessary
|
|
206
|
-
|
|
207
|
-
async function loadIndexes(
|
|
208
|
-
me: NamedNode | string,
|
|
209
|
-
publicProfile: NamedNode | string | null,
|
|
210
|
-
preferencesFile: NamedNode | string | null,
|
|
211
|
-
onWarning = async (_err: Error) => {
|
|
212
|
-
return undefined;
|
|
213
|
-
}
|
|
214
|
-
): Promise<{
|
|
215
|
-
private: any;
|
|
216
|
-
public: any;
|
|
217
|
-
}> {
|
|
218
|
-
let privateIndexes: any[] = [];
|
|
219
|
-
let publicIndexes: any[] = [];
|
|
220
|
-
if (publicProfile) {
|
|
221
|
-
publicIndexes = getTypeIndex(me, publicProfile, true);
|
|
222
|
-
try {
|
|
223
|
-
await store.fetcher.load(publicIndexes as NamedNode[]);
|
|
224
|
-
} catch (err) {
|
|
225
|
-
onWarning(new Error(`loadIndex: loading public type index(es) ${err}`));
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
if (preferencesFile) {
|
|
229
|
-
privateIndexes = getTypeIndex(me, preferencesFile, false);
|
|
230
|
-
// console.log({ privateIndexes })
|
|
231
|
-
if (privateIndexes.length === 0) {
|
|
232
|
-
await onWarning(
|
|
233
|
-
new Error(
|
|
234
|
-
`Your preference file ${preferencesFile} does not point to a private type index.`
|
|
235
|
-
)
|
|
236
|
-
);
|
|
237
|
-
} else {
|
|
238
|
-
try {
|
|
239
|
-
await store.fetcher.load(privateIndexes);
|
|
240
|
-
} catch (err) {
|
|
241
|
-
onWarning(
|
|
242
|
-
new Error(`loadIndex: loading private type index(es) ${err}`)
|
|
243
|
-
);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
// } else {
|
|
247
|
-
// debug.log(
|
|
248
|
-
// 'We know your preference file is not available, so we are not bothering with private type indexes.'
|
|
249
|
-
// )
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
return {
|
|
253
|
-
private: privateIndexes,
|
|
254
|
-
public: publicIndexes,
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
function getTypeIndex(
|
|
259
|
-
me: NamedNode | string,
|
|
260
|
-
preferencesFile: NamedNode | string,
|
|
261
|
-
isPublic: boolean
|
|
262
|
-
): NamedNode[] {
|
|
263
|
-
// console.log('getTypeIndex', store.each(me, undefined, undefined, preferencesFile), isPublic, preferencesFile)
|
|
264
|
-
return store.each(
|
|
265
|
-
me as NamedNode,
|
|
266
|
-
isPublic ? ns.solid("publicTypeIndex") : ns.solid("privateTypeIndex"),
|
|
267
|
-
undefined,
|
|
268
|
-
preferencesFile as NamedNode
|
|
269
|
-
) as NamedNode[];
|
|
270
|
-
}
|
|
271
9
|
|
|
272
10
|
function getRegistrations(instance, theClass) {
|
|
273
11
|
return store
|
|
@@ -385,7 +123,7 @@ export function createTypeIndexLogic(store, authn, profileLogic, utilityLogic) {
|
|
|
385
123
|
* used in chat in bookmark.js (solid-ui)
|
|
386
124
|
* Returns the registration object if successful else null
|
|
387
125
|
*/
|
|
388
|
-
async function
|
|
126
|
+
async function registerInTypeIndex(
|
|
389
127
|
instance: NamedNode,
|
|
390
128
|
index: NamedNode,
|
|
391
129
|
theClass: NamedNode,
|
|
@@ -415,7 +153,7 @@ export function createTypeIndexLogic(store, authn, profileLogic, utilityLogic) {
|
|
|
415
153
|
await store.updater.update(statements, [])
|
|
416
154
|
}
|
|
417
155
|
|
|
418
|
-
async function getScopedAppsFromIndex(scope, theClass: NamedNode | null) {
|
|
156
|
+
async function getScopedAppsFromIndex(scope: TypeIndexScope, theClass: NamedNode | null): Promise<ScopedApp[]> {
|
|
419
157
|
const index = scope.index
|
|
420
158
|
const registrations = store.statementsMatching(null, ns.solid('instance'), null, index)
|
|
421
159
|
.concat(store.statementsMatching(null, ns.solid('instanceContainer'), null, index))
|
|
@@ -441,15 +179,7 @@ export function createTypeIndexLogic(store, authn, profileLogic, utilityLogic) {
|
|
|
441
179
|
}
|
|
442
180
|
|
|
443
181
|
return {
|
|
444
|
-
ensureTypeIndexes,
|
|
445
|
-
loadTypeIndexes,
|
|
446
182
|
registerInTypeIndex,
|
|
447
|
-
loadIndex,
|
|
448
|
-
ensureOneTypeIndex,
|
|
449
|
-
putIndex,
|
|
450
|
-
makeIndexIfNecessary,
|
|
451
|
-
loadIndexes,
|
|
452
|
-
getTypeIndex,
|
|
453
183
|
getRegistrations,
|
|
454
184
|
loadTypeIndexesFor,
|
|
455
185
|
loadCommunityTypeIndexes,
|
|
@@ -458,7 +188,6 @@ export function createTypeIndexLogic(store, authn, profileLogic, utilityLogic) {
|
|
|
458
188
|
getAppInstances,
|
|
459
189
|
suggestPublicTypeIndex,
|
|
460
190
|
suggestPrivateTypeIndex,
|
|
461
|
-
registerInstanceInTypeIndex,
|
|
462
191
|
deleteTypeIndexRegistration,
|
|
463
192
|
getScopedAppsFromIndex
|
|
464
193
|
}
|
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
|
|
@@ -45,3 +45,78 @@ export interface CreatedPaneOptions {
|
|
|
45
45
|
newInstance: NamedNode;
|
|
46
46
|
}
|
|
47
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
|
+
|
|
@@ -6,44 +6,43 @@ import { NamedNode, Statement, sym } from "rdflib";
|
|
|
6
6
|
export function createContainerLogic(store) {
|
|
7
7
|
|
|
8
8
|
function getContainerElements(containerNode: NamedNode): NamedNode[] {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
.map((st: Statement) => st.object as 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);
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
function isContainer(url:
|
|
20
|
-
|
|
18
|
+
function isContainer(url: NamedNode) {
|
|
19
|
+
const nodeToString = url.value;
|
|
20
|
+
return nodeToString.charAt(nodeToString.length - 1) === "/";
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
async function createContainer(url: string) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
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
|
+
}
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
async function getContainerMembers(containerUrl:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const nodes = getContainerElements(containerNode);
|
|
46
|
-
return nodes.map(node => node.value);
|
|
43
|
+
async function getContainerMembers(containerUrl: NamedNode): Promise<NamedNode[]> {
|
|
44
|
+
await store.fetcher.load(containerUrl);
|
|
45
|
+
return getContainerElements(containerUrl);
|
|
47
46
|
}
|
|
48
47
|
return {
|
|
49
48
|
isContainer,
|
package/src/util/{ns.js → ns.ts}
RENAMED
|
File without changes
|
package/src/util/utilityLogic.ts
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import { NamedNode, st } from "rdflib";
|
|
1
|
+
import { NamedNode, st, sym } from "rdflib";
|
|
2
2
|
import { CrossOriginForbiddenError, FetchError, NotEditableError, SameOriginForbiddenError, UnauthorizedError, WebOperationError } from "../logic/CustomError";
|
|
3
3
|
import * as debug from '../util/debug';
|
|
4
4
|
import { differentOrigin } from "./utils";
|
|
5
5
|
|
|
6
6
|
export function createUtilityLogic(store, aclLogic, containerLogic) {
|
|
7
7
|
|
|
8
|
-
async function recursiveDelete(
|
|
8
|
+
async function recursiveDelete(containerNode: NamedNode) {
|
|
9
9
|
try {
|
|
10
|
-
if (containerLogic.isContainer(
|
|
11
|
-
const aclDocUrl = await aclLogic.findAclDocUrl(
|
|
10
|
+
if (containerLogic.isContainer(containerNode)) {
|
|
11
|
+
const aclDocUrl = await aclLogic.findAclDocUrl(containerNode)
|
|
12
12
|
await store.fetcher._fetch(aclDocUrl, { method: "DELETE" });
|
|
13
|
-
const containerMembers = await containerLogic.getContainerMembers(
|
|
13
|
+
const containerMembers = await containerLogic.getContainerMembers(containerNode);
|
|
14
14
|
await Promise.all(
|
|
15
15
|
containerMembers.map((url) => recursiveDelete(url))
|
|
16
16
|
);
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
const nodeToStringHere = containerNode.value;
|
|
19
|
+
return store.fetcher._fetch(nodeToStringHere, { method: "DELETE" });
|
|
19
20
|
} catch (e) {
|
|
20
21
|
// debug.log(`Please manually remove ${url} from your system under test.`, e);
|
|
21
22
|
}
|
|
@@ -126,7 +127,7 @@ export function createUtilityLogic(store, aclLogic, containerLogic) {
|
|
|
126
127
|
''
|
|
127
128
|
].join('\n')
|
|
128
129
|
}
|
|
129
|
-
const aclDocUrl = await aclLogic.findAclDocUrl(options.target)
|
|
130
|
+
const aclDocUrl = await aclLogic.findAclDocUrl(sym(options.target))
|
|
130
131
|
return store.fetcher._fetch(aclDocUrl, {
|
|
131
132
|
method: 'PUT',
|
|
132
133
|
body: str,
|