@noeldemartin/solid-utils 0.1.1 → 0.2.0

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.
Files changed (35) hide show
  1. package/.nvmrc +1 -0
  2. package/.semaphore/semaphore.yml +1 -1
  3. package/dist/noeldemartin-solid-utils.cjs.js +1 -1
  4. package/dist/noeldemartin-solid-utils.cjs.js.map +1 -1
  5. package/dist/noeldemartin-solid-utils.d.ts +94 -16
  6. package/dist/noeldemartin-solid-utils.esm.js +1 -1
  7. package/dist/noeldemartin-solid-utils.esm.js.map +1 -1
  8. package/dist/noeldemartin-solid-utils.umd.js +90 -0
  9. package/dist/noeldemartin-solid-utils.umd.js.map +1 -0
  10. package/noeldemartin.config.js +4 -2
  11. package/package.json +11 -11
  12. package/src/errors/MalformedSolidDocumentError.ts +2 -2
  13. package/src/errors/NetworkRequestError.ts +5 -4
  14. package/src/errors/NotFoundError.ts +2 -2
  15. package/src/errors/UnauthorizedError.ts +2 -2
  16. package/src/errors/UnsuccessfulNetworkRequestError.ts +23 -0
  17. package/src/errors/UnsupportedAuthorizationProtocolError.ts +16 -0
  18. package/src/errors/index.ts +2 -0
  19. package/src/helpers/auth.ts +91 -18
  20. package/src/helpers/identifiers.ts +56 -0
  21. package/src/helpers/index.ts +2 -0
  22. package/src/helpers/interop.ts +68 -30
  23. package/src/helpers/io.ts +147 -60
  24. package/src/helpers/jsonld.ts +25 -1
  25. package/src/helpers/testing.ts +103 -28
  26. package/src/helpers/vocabs.ts +4 -2
  27. package/src/helpers/wac.ts +55 -0
  28. package/src/models/SolidDocument.ts +41 -35
  29. package/src/models/SolidStore.ts +61 -0
  30. package/src/models/index.ts +2 -1
  31. package/src/plugins/chai/assertions.ts +11 -2
  32. package/src/plugins/cypress/types.d.ts +1 -0
  33. package/src/plugins/jest/matchers.ts +45 -32
  34. package/src/plugins/jest/types.d.ts +1 -0
  35. package/src/types/n3.d.ts +9 -0
@@ -1,7 +1,9 @@
1
- module.exports = {
1
+ const { defineConfig } = require('@noeldemartin/scripts');
2
+
3
+ module.exports = defineConfig({
2
4
  name: 'NoelDeMartinSolidUtils',
3
5
  declarations: [
4
6
  // 'src/plugins/cypress/types.d.ts',
5
7
  'src/plugins/jest/types.d.ts',
6
8
  ],
7
- };
9
+ });
package/package.json CHANGED
@@ -1,26 +1,27 @@
1
1
  {
2
2
  "name": "@noeldemartin/solid-utils",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "My JavaScript utilities for Solid",
5
5
  "main": "dist/noeldemartin-solid-utils.cjs.js",
6
6
  "module": "dist/noeldemartin-solid-utils.esm.js",
7
+ "browser": "dist/noeldemartin-solid-utils.umd.js",
7
8
  "types": "dist/noeldemartin-solid-utils.d.ts",
8
9
  "scripts": {
9
10
  "build": "rm dist -rf && npm run build:js && npm run build:types",
10
11
  "build:js": "noeldemartin-build-javascript",
11
12
  "build:types": "noeldemartin-build-types",
12
- "lint": "eslint src",
13
+ "lint": "noeldemartin-lint src",
13
14
  "publish-next": "noeldemartin-publish-next",
14
15
  "test": "jest --verbose",
15
16
  "test:coverage": "jest --coverage"
16
17
  },
17
- "engines": {
18
- "node": ">=14.x"
19
- },
20
18
  "repository": {
21
19
  "type": "git",
22
20
  "url": "git+https://github.com/noeldemartin/solid-utils.git"
23
21
  },
22
+ "engines": {
23
+ "node": ">=14.x"
24
+ },
24
25
  "author": "Noel De Martin",
25
26
  "license": "MIT",
26
27
  "bugs": {
@@ -29,12 +30,12 @@
29
30
  "homepage": "https://github.com/noeldemartin/solid-utils",
30
31
  "dependencies": {
31
32
  "@babel/runtime": "^7.14.0",
32
- "@noeldemartin/utils": "^0.2.1",
33
+ "@noeldemartin/solid-utils-external": "^0.1.0",
34
+ "@noeldemartin/utils": "^0.3.0",
33
35
  "@types/rdf-js": "^4.0.1",
34
36
  "core-js": "^3.12.1",
35
37
  "jest-diff": "^26.6.2",
36
- "md5": "^2.3.0",
37
- "n3": "^1.10.0"
38
+ "md5": "^2.3.0"
38
39
  },
39
40
  "devDependencies": {
40
41
  "@babel/core": "^7.14.3",
@@ -43,8 +44,8 @@
43
44
  "@babel/preset-env": "^7.14.2",
44
45
  "@babel/preset-typescript": "^7.13.0",
45
46
  "@microsoft/api-extractor": "^7.15.2",
46
- "@noeldemartin/eslint-config-typescript": "^0.1.0",
47
- "@noeldemartin/scripts": "^0.1.1",
47
+ "@noeldemartin/eslint-config-typescript": "^0.1.1",
48
+ "@noeldemartin/scripts": "^0.1.2",
48
49
  "@rollup/plugin-alias": "^3.1.2",
49
50
  "@rollup/plugin-babel": "^5.3.0",
50
51
  "@rollup/plugin-commonjs": "^19.0.0",
@@ -54,7 +55,6 @@
54
55
  "@types/jest": "^26.0.23",
55
56
  "@types/jest-diff": "^24.3.0",
56
57
  "@types/md5": "^2.3.0",
57
- "@types/n3": "^1.8.0",
58
58
  "babel-plugin-transform-remove-imports": "^1.5.4",
59
59
  "eslint": "^7.26.0",
60
60
  "jest": "^26.6.3",
@@ -1,4 +1,4 @@
1
- import { Error } from '@noeldemartin/utils';
1
+ import { JSError } from '@noeldemartin/utils';
2
2
 
3
3
  function errorMessage(
4
4
  documentUrl: string | null,
@@ -14,7 +14,7 @@ export enum SolidDocumentFormat {
14
14
  Turtle = 'Turtle',
15
15
  }
16
16
 
17
- export default class MalformedSolidDocumentError extends Error {
17
+ export default class MalformedSolidDocumentError extends JSError {
18
18
 
19
19
  public readonly documentUrl: string | null;
20
20
  public readonly documentFormat: SolidDocumentFormat;
@@ -1,11 +1,12 @@
1
- import { Error } from '@noeldemartin/utils';
1
+ import { JSError } from '@noeldemartin/utils';
2
+ import type { JSErrorOptions } from '@noeldemartin/utils';
2
3
 
3
- export default class NetworkRequestError extends Error {
4
+ export default class NetworkRequestError extends JSError {
4
5
 
5
6
  public readonly url: string;
6
7
 
7
- constructor(url: string) {
8
- super(`Request failed trying to fetch ${url}`);
8
+ constructor(url: string, options?: JSErrorOptions) {
9
+ super(`Request failed trying to fetch ${url}`, options);
9
10
 
10
11
  this.url = url;
11
12
  }
@@ -1,6 +1,6 @@
1
- import { Error } from '@noeldemartin/utils';
1
+ import { JSError } from '@noeldemartin/utils';
2
2
 
3
- export default class NotFoundError extends Error {
3
+ export default class NotFoundError extends JSError {
4
4
 
5
5
  public readonly url: string;
6
6
 
@@ -1,4 +1,4 @@
1
- import { Error } from '@noeldemartin/utils';
1
+ import { JSError } from '@noeldemartin/utils';
2
2
 
3
3
  function errorMessage(url: string, responseStatus?: number): string {
4
4
  const typeInfo = responseStatus === 403 ? ' (Forbidden)' : '';
@@ -6,7 +6,7 @@ function errorMessage(url: string, responseStatus?: number): string {
6
6
  return `Unauthorized${typeInfo}: ${url}`;
7
7
  }
8
8
 
9
- export default class UnauthorizedError extends Error {
9
+ export default class UnauthorizedError extends JSError {
10
10
 
11
11
  public readonly url: string;
12
12
  public readonly responseStatus?: number;
@@ -0,0 +1,23 @@
1
+ import { JSError } from '@noeldemartin/utils';
2
+
3
+ function getErrorMessage(messageOrResponse: string | Response, response?: Response): string {
4
+ response = response ?? messageOrResponse as Response;
5
+
6
+ return typeof messageOrResponse === 'string'
7
+ ? `${messageOrResponse} (returned ${response.status} status code)`
8
+ : `Request to ${response.url} returned ${response.status} status code`;
9
+ }
10
+
11
+ export default class UnsuccessfulRequestError extends JSError {
12
+
13
+ public response: Response;
14
+
15
+ constructor(response: Response);
16
+ constructor(message: string, response: Response);
17
+ constructor(messageOrResponse: string | Response, response?: Response) {
18
+ super(getErrorMessage(messageOrResponse, response));
19
+
20
+ this.response = response ?? messageOrResponse as Response;
21
+ }
22
+
23
+ }
@@ -0,0 +1,16 @@
1
+ import { JSError } from '@noeldemartin/utils';
2
+ import type { JSErrorOptions } from '@noeldemartin/utils';
3
+
4
+ export default class UnsupportedAuthorizationProtocolError extends JSError {
5
+
6
+ public readonly url: string;
7
+ public readonly protocol: string;
8
+
9
+ constructor(url: string, protocol: string, options?: JSErrorOptions) {
10
+ super(`The resource at ${url} is using an unsupported authorization protocol (${protocol})`, options);
11
+
12
+ this.url = url;
13
+ this.protocol = protocol;
14
+ }
15
+
16
+ }
@@ -2,3 +2,5 @@ export { default as MalformedSolidDocumentError, SolidDocumentFormat } from './M
2
2
  export { default as NetworkRequestError } from './NetworkRequestError';
3
3
  export { default as NotFoundError } from './NotFoundError';
4
4
  export { default as UnauthorizedError } from './UnauthorizedError';
5
+ export { default as UnsuccessfulNetworkRequestError } from './UnsuccessfulNetworkRequestError';
6
+ export { default as UnsupportedAuthorizationProtocolError } from './UnsupportedAuthorizationProtocolError';
@@ -1,4 +1,8 @@
1
- import { objectWithoutEmpty, silenced, urlParentDirectory, urlRoot, urlRoute } from '@noeldemartin/utils';
1
+ import { arrayUnique, objectWithoutEmpty, silenced, urlParentDirectory, urlRoot, urlRoute } from '@noeldemartin/utils';
2
+
3
+ import SolidStore from '../models/SolidStore';
4
+ import UnauthorizedError from '../errors/UnauthorizedError';
5
+ import type SolidDocument from '../models/SolidDocument';
2
6
 
3
7
  import { fetchSolidDocument } from './io';
4
8
  import type { Fetch } from './io';
@@ -6,6 +10,8 @@ import type { Fetch } from './io';
6
10
  export interface SolidUserProfile {
7
11
  webId: string;
8
12
  storageUrls: string[];
13
+ cloaked: boolean;
14
+ writableProfileUrl: string | null;
9
15
  name?: string;
10
16
  avatarUrl?: string;
11
17
  oidcIssuerUrl?: string;
@@ -13,16 +19,79 @@ export interface SolidUserProfile {
13
19
  privateTypeIndexUrl?: string;
14
20
  }
15
21
 
22
+ async function fetchExtendedUserProfile(webIdDocument: SolidDocument, fetch?: Fetch): Promise<{
23
+ store: SolidStore;
24
+ cloaked: boolean;
25
+ writableProfileUrl: string | null;
26
+ }> {
27
+ const store = new SolidStore(webIdDocument.getQuads());
28
+ const documents: Record<string, SolidDocument | false | null> = { [webIdDocument.url]: webIdDocument };
29
+ const addReferencedDocumentUrls = (document: SolidDocument) => {
30
+ document
31
+ .statements(undefined, 'foaf:isPrimaryTopicOf')
32
+ .map(quad => quad.object.value)
33
+ .forEach(profileDocumentUrl => documents[profileDocumentUrl] = documents[profileDocumentUrl] ?? null);
34
+ document
35
+ .statements(undefined, 'foaf:primaryTopic')
36
+ .map(quad => quad.subject.value)
37
+ .forEach(profileDocumentUrl => documents[profileDocumentUrl] = documents[profileDocumentUrl] ?? null);
38
+ };
39
+ const loadProfileDocuments = async (): Promise<void> => {
40
+ for (const [url, document] of Object.entries(documents)) {
41
+ if (document !== null) {
42
+ continue;
43
+ }
44
+
45
+ try {
46
+ const document = await fetchSolidDocument(url, fetch);
47
+
48
+ documents[url] = document;
49
+ store.addQuads(document.getQuads());
50
+
51
+ addReferencedDocumentUrls(document);
52
+ } catch (error) {
53
+ if (error instanceof UnauthorizedError) {
54
+ documents[url] = false;
55
+
56
+ continue;
57
+ }
58
+
59
+ throw error;
60
+ }
61
+ }
62
+ };
63
+
64
+ addReferencedDocumentUrls(webIdDocument);
65
+
66
+ do {
67
+ await loadProfileDocuments();
68
+ } while (Object.values(documents).some(document => document === null));
69
+
70
+ return {
71
+ store,
72
+ cloaked: Object.values(documents).some(document => document === false),
73
+ writableProfileUrl:
74
+ webIdDocument.isUserWritable()
75
+ ? webIdDocument.url
76
+ : Object
77
+ .values(documents)
78
+ .find((document): document is SolidDocument => !!document && document.isUserWritable())
79
+ ?.url ?? null,
80
+ };
81
+ }
82
+
16
83
  async function fetchUserProfile(webId: string, fetch?: Fetch): Promise<SolidUserProfile> {
17
84
  const documentUrl = urlRoute(webId);
18
85
  const document = await fetchSolidDocument(documentUrl, fetch);
19
86
 
20
- if (!document.isPersonalProfile())
21
- throw new Error(`Document at ${documentUrl} is not a profile.`);
87
+ if (!document.isPersonalProfile() && !document.contains(webId, 'solid:oidcIssuer')) {
88
+ throw new Error(`${webId} is not a valid webId.`);
89
+ }
22
90
 
23
- const storageUrls = document.statements(webId, 'pim:storage').map(storage => storage.object.value);
24
- const publicTypeIndex = document.statement(webId, 'solid:publicTypeIndex');
25
- const privateTypeIndex = document.statement(webId, 'solid:privateTypeIndex');
91
+ const { store, writableProfileUrl, cloaked } = await fetchExtendedUserProfile(document, fetch);
92
+ const storageUrls = store.statements(webId, 'pim:storage').map(storage => storage.object.value);
93
+ const publicTypeIndex = store.statement(webId, 'solid:publicTypeIndex');
94
+ const privateTypeIndex = store.statement(webId, 'solid:privateTypeIndex');
26
95
 
27
96
  let parentUrl = urlParentDirectory(documentUrl);
28
97
  while (parentUrl && storageUrls.length === 0) {
@@ -37,19 +106,23 @@ async function fetchUserProfile(webId: string, fetch?: Fetch): Promise<SolidUser
37
106
  parentUrl = urlParentDirectory(parentUrl);
38
107
  }
39
108
 
40
- return objectWithoutEmpty({
109
+ return {
41
110
  webId,
42
- storageUrls,
43
- name:
44
- document.statement(webId, 'vcard:fn')?.object.value ??
45
- document.statement(webId, 'foaf:name')?.object.value,
46
- avatarUrl:
47
- document.statement(webId, 'vcard:hasPhoto')?.object.value ??
48
- document.statement(webId, 'foaf:img')?.object.value,
49
- oidcIssuerUrl: document.statement(webId, 'solid:oidcIssuer')?.object.value,
50
- publicTypeIndexUrl: publicTypeIndex?.object.value,
51
- privateTypeIndexUrl: privateTypeIndex?.object.value,
52
- });
111
+ cloaked,
112
+ writableProfileUrl,
113
+ storageUrls: arrayUnique(storageUrls),
114
+ ...objectWithoutEmpty({
115
+ name:
116
+ store.statement(webId, 'vcard:fn')?.object.value ??
117
+ store.statement(webId, 'foaf:name')?.object.value,
118
+ avatarUrl:
119
+ store.statement(webId, 'vcard:hasPhoto')?.object.value ??
120
+ store.statement(webId, 'foaf:img')?.object.value,
121
+ oidcIssuerUrl: store.statement(webId, 'solid:oidcIssuer')?.object.value,
122
+ publicTypeIndexUrl: publicTypeIndex?.object.value,
123
+ privateTypeIndexUrl: privateTypeIndex?.object.value,
124
+ }),
125
+ };
53
126
  }
54
127
 
55
128
  export async function fetchLoginUserProfile(loginUrl: string, fetch?: Fetch): Promise<SolidUserProfile | null> {
@@ -0,0 +1,56 @@
1
+ import { arr, isArray, isObject, objectDeepClone, objectWithoutEmpty, tap, urlParse, uuid } from '@noeldemartin/utils';
2
+ import type { UrlParts } from '@noeldemartin/utils';
3
+ import type { JsonLD, JsonLDResource } from '@/helpers';
4
+
5
+ export interface SubjectParts {
6
+ containerUrl?: string;
7
+ documentName?: string;
8
+ resourceHash?: string;
9
+ }
10
+
11
+ function getContainerPath(parts: UrlParts): string | null {
12
+ if (!parts.path || !parts.path.startsWith('/'))
13
+ return null;
14
+
15
+ if (parts.path.match(/^\/[^/]*$/))
16
+ return '/';
17
+
18
+ return `/${arr(parts.path.split('/')).filter().slice(0, -1).join('/')}/`.replace('//', '/');
19
+ }
20
+
21
+ function getContainerUrl(parts: UrlParts): string | null {
22
+ const containerPath = getContainerPath(parts);
23
+
24
+ return parts.protocol && parts.domain
25
+ ? `${parts.protocol}://${parts.domain}${containerPath ?? '/'}`
26
+ : containerPath;
27
+ }
28
+
29
+ function __mintJsonLDIdentifiers(jsonld: JsonLD): void {
30
+ if (!('@type' in jsonld) || '@value' in jsonld)
31
+ return;
32
+
33
+ jsonld['@id'] = jsonld['@id'] ?? uuid();
34
+
35
+ for (const propertyValue of Object.values(jsonld)) {
36
+ if (isObject(propertyValue))
37
+ __mintJsonLDIdentifiers(propertyValue);
38
+
39
+ if (isArray(propertyValue))
40
+ propertyValue.forEach(value => isObject(value) && __mintJsonLDIdentifiers(value));
41
+ }
42
+ }
43
+
44
+ export function mintJsonLDIdentifiers(jsonld: JsonLD): JsonLDResource {
45
+ return tap(objectDeepClone(jsonld) as JsonLDResource, clone => __mintJsonLDIdentifiers(clone));
46
+ }
47
+
48
+ export function parseResourceSubject(subject: string): SubjectParts {
49
+ const parts = urlParse(subject);
50
+
51
+ return !parts ? {} : objectWithoutEmpty({
52
+ containerUrl: getContainerUrl(parts),
53
+ documentName: parts.path ? parts.path.split('/').pop() : null,
54
+ resourceHash: parts.fragment,
55
+ });
56
+ }
@@ -1,6 +1,8 @@
1
1
  export * from './auth';
2
+ export * from './identifiers';
2
3
  export * from './interop';
3
4
  export * from './io';
4
5
  export * from './jsonld';
5
6
  export * from './testing';
6
7
  export * from './vocabs';
8
+ export * from './wac';
@@ -1,57 +1,95 @@
1
1
  import { uuid } from '@noeldemartin/utils';
2
2
 
3
3
  import { createSolidDocument, fetchSolidDocument, solidDocumentExists, updateSolidDocument } from '@/helpers/io';
4
- import type SolidThing from '@/models/SolidThing';
5
4
  import type { Fetch } from '@/helpers/io';
6
5
  import type { SolidUserProfile } from '@/helpers/auth';
7
6
 
8
- async function mintPrivateTypeIndexUrl(user: SolidUserProfile, fetch?: Fetch): Promise<string> {
9
- fetch = fetch ?? window.fetch;
7
+ type TypeIndexType = 'public' | 'private';
8
+
9
+ async function mintTypeIndexUrl(user: SolidUserProfile, type: TypeIndexType, fetch?: Fetch): Promise<string> {
10
+ fetch = fetch ?? window.fetch.bind(fetch);
10
11
 
11
12
  const storageUrl = user.storageUrls[0];
12
- const typeIndexUrl = `${storageUrl}settings/privateTypeIndex`;
13
+ const typeIndexUrl = `${storageUrl}settings/${type}TypeIndex`;
13
14
 
14
15
  return await solidDocumentExists(typeIndexUrl, fetch)
15
- ? `${storageUrl}settings/privateTypeIndex-${uuid()}`
16
+ ? `${storageUrl}settings/${type}TypeIndex-${uuid()}`
16
17
  : typeIndexUrl;
17
18
  }
18
19
 
19
- export async function createPrivateTypeIndex(user: SolidUserProfile, fetch?: Fetch): Promise<string> {
20
- fetch = fetch ?? window.fetch;
20
+ async function createTypeIndex(user: SolidUserProfile, type: TypeIndexType, fetch?: Fetch) {
21
+ if (user.writableProfileUrl === null) {
22
+ throw new Error('Can\'t create type index without a writable profile document');
23
+ }
21
24
 
22
- const typeIndexUrl = await mintPrivateTypeIndexUrl(user, fetch);
23
- const typeIndexBody = `
24
- <> a
25
- <http://www.w3.org/ns/solid/terms#TypeIndex>,
26
- <http://www.w3.org/ns/solid/terms#UnlistedDocument> .
27
- `;
25
+ fetch = fetch ?? window.fetch.bind(fetch);
26
+
27
+ const typeIndexUrl = await mintTypeIndexUrl(user, type, fetch);
28
+ const typeIndexBody = type === 'public'
29
+ ? '<> a <http://www.w3.org/ns/solid/terms#TypeIndex> .'
30
+ : `
31
+ <> a
32
+ <http://www.w3.org/ns/solid/terms#TypeIndex>,
33
+ <http://www.w3.org/ns/solid/terms#UnlistedDocument> .
34
+ `;
28
35
  const profileUpdateBody = `
29
36
  INSERT DATA {
30
- <${user.webId}> <http://www.w3.org/ns/solid/terms#privateTypeIndex> <${typeIndexUrl}> .
37
+ <${user.webId}> <http://www.w3.org/ns/solid/terms#${type}TypeIndex> <${typeIndexUrl}> .
31
38
  }
32
39
  `;
33
40
 
34
- createSolidDocument(typeIndexUrl, typeIndexBody, fetch);
35
- updateSolidDocument(user.webId, profileUpdateBody, fetch);
41
+ await Promise.all([
42
+ createSolidDocument(typeIndexUrl, typeIndexBody, fetch),
43
+ updateSolidDocument(user.writableProfileUrl, profileUpdateBody, fetch),
44
+ ]);
45
+
46
+ if (type === 'public') {
47
+ // TODO Implement updating ACLs for the listing itself to public
48
+ }
36
49
 
37
50
  return typeIndexUrl;
38
51
  }
39
52
 
40
- export async function findContainerRegistration(
53
+ async function findRegistrations(
41
54
  typeIndexUrl: string,
42
- childrenType: string,
55
+ type: string | string[],
56
+ predicate: string,
43
57
  fetch?: Fetch,
44
- ): Promise<SolidThing | null> {
58
+ ): Promise<string[]> {
45
59
  const typeIndex = await fetchSolidDocument(typeIndexUrl, fetch);
46
- const containerQuad = typeIndex
47
- .statements(undefined, 'rdfs:type', 'solid:TypeRegistration')
48
- .find(
49
- statement =>
50
- typeIndex.contains(statement.subject.value, 'solid:forClass', childrenType) &&
51
- typeIndex.contains(statement.subject.value, 'solid:instanceContainer'),
52
- );
53
-
54
- return containerQuad
55
- ? typeIndex.getThing(containerQuad.subject.value) ?? null
56
- : null;
60
+ const types = Array.isArray(type) ? type : [type];
61
+
62
+ return types.map(
63
+ type => typeIndex
64
+ .statements(undefined, 'rdf:type', 'solid:TypeRegistration')
65
+ .filter(statement => typeIndex.contains(statement.subject.value, 'solid:forClass', type))
66
+ .map(statement => typeIndex.statements(statement.subject.value, predicate))
67
+ .flat()
68
+ .map(statement => statement.object.value)
69
+ .filter(url => !!url),
70
+ ).flat();
71
+ }
72
+
73
+ export async function createPublicTypeIndex(user: SolidUserProfile, fetch?: Fetch): Promise<string> {
74
+ return createTypeIndex(user, 'public', fetch);
75
+ }
76
+
77
+ export async function createPrivateTypeIndex(user: SolidUserProfile, fetch?: Fetch): Promise<string> {
78
+ return createTypeIndex(user, 'private', fetch);
79
+ }
80
+
81
+ export async function findContainerRegistrations(
82
+ typeIndexUrl: string,
83
+ type: string | string[],
84
+ fetch?: Fetch,
85
+ ): Promise<string[]> {
86
+ return findRegistrations(typeIndexUrl, type, 'solid:instanceContainer', fetch);
87
+ }
88
+
89
+ export async function findInstanceRegistrations(
90
+ typeIndexUrl: string,
91
+ type: string | string[],
92
+ fetch?: Fetch,
93
+ ): Promise<string[]> {
94
+ return findRegistrations(typeIndexUrl, type, 'solid:instance', fetch);
57
95
  }