diff --git a/app/lib/class/AccessControl.ts b/app/lib/class/AccessControl.ts deleted file mode 100644 index 6dbce93..0000000 --- a/app/lib/class/AccessControl.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { SetFrom, TermAs, TermFrom } from "@rdfjs/wrapper" -import { Policy } from "@/app/lib/class/Policy" -import { ACP } from "@/app/lib/class/Vocabulary" -import { Typed } from "@/app/lib/class/Typed"; - -export class AccessControl extends Typed { - get apply(): Set { - return SetFrom.subjectPredicate(this, ACP.apply, TermAs.instance(Policy), TermFrom.instance) - } -} diff --git a/app/lib/class/AccessControlResource.ts b/app/lib/class/AccessControlResource.ts deleted file mode 100644 index fb56dc0..0000000 --- a/app/lib/class/AccessControlResource.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { NamedNodeAs, NamedNodeFrom, OptionalAs, OptionalFrom, SetFrom, TermAs, TermFrom } from "@rdfjs/wrapper" -import { AccessControl } from "@/app/lib/class/AccessControl" -import { ACP } from "@/app/lib/class/Vocabulary" -import { Typed } from "@/app/lib/class/Typed" - -export class AccessControlResource extends Typed { - get accessControl(): Set { - return SetFrom.subjectPredicate(this, ACP.accessControl, TermAs.instance(AccessControl), TermFrom.instance) - } - - get resource(): string | undefined { - return OptionalFrom.subjectPredicate(this, ACP.resource, NamedNodeAs.string) - } - - set resource(v: string) { - OptionalAs.object(this, ACP.resource, v, NamedNodeFrom.string) - } -} diff --git a/app/lib/class/AcrDataset.ts b/app/lib/class/AcrDataset.ts deleted file mode 100644 index 5009eed..0000000 --- a/app/lib/class/AcrDataset.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { DatasetWrapper } from "@rdfjs/wrapper" -import { AccessControlResource } from "@/app/lib/class/AccessControlResource"; -import { ACP } from "@/app/lib/class/Vocabulary" - -export class AcrDataset extends DatasetWrapper { - get acr(): AccessControlResource | undefined { - const subjects = new Set([ - ...this.instancesOf(ACP.AccessControlResource, AccessControlResource), - ...this.subjectsOf(ACP.resource, AccessControlResource), - ...this.subjectsOf(ACP.accessControl, AccessControlResource), - ...this.subjectsOf(ACP.memberAccessControl, AccessControlResource) - ]) - - for (const subject of subjects) { - return subject - } - } -} diff --git a/app/lib/class/Agent.ts b/app/lib/class/Agent.ts deleted file mode 100644 index 6c0ba19..0000000 --- a/app/lib/class/Agent.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { LiteralAs, NamedNodeAs, NamedNodeFrom, OptionalFrom, SetFrom, TermAs, TermWrapper } from "@rdfjs/wrapper" -import { FOAF, PIM, SOLID, VCARD } from "@/app/lib/class/Vocabulary" - -export class Agent extends TermWrapper { - get vcardFn(): string | undefined { - return OptionalFrom.subjectPredicate(this, VCARD.fn, LiteralAs.string) - } - - get vcardHasUrl(): string | undefined { - return OptionalFrom.subjectPredicate(this, VCARD.hasUrl, NamedNodeAs.string) - } - - get organization(): string | null { - return OptionalFrom.subjectPredicate(this, VCARD.organizationName, NamedNodeAs.string) ?? null - } - - get role(): string | null { - return OptionalFrom.subjectPredicate(this, VCARD.role, NamedNodeAs.string) ?? null - } - - get title(): string | null { - return OptionalFrom.subjectPredicate(this, VCARD.title, LiteralAs.string) ?? null - } - - get phone(): string | null { - return this.hasTelephone?.actualValue ?? null - } - - get hasTelephone(): HasValue | undefined { - return OptionalFrom.subjectPredicate(this, VCARD.hasTelephone, TermAs.instance(HasValue)) - } - - get foafName(): string | undefined { - return OptionalFrom.subjectPredicate(this, FOAF.fname, LiteralAs.string) - } - - get name(): string | null { - return this.vcardFn ?? this.foafName ?? this.value.split("/").pop()?.split("#")[0] ?? null - } - - get storageUrls(): Set { - // TODO: When available - this.pimStorage.union(this.solidStorage) - return new Set([...this.pimStorage, ...this.solidStorage]) - } - - get foafHomepage(): string | undefined { - return OptionalFrom.subjectPredicate(this, FOAF.homepage, LiteralAs.string) - } - - get website(): string | null { - return this.vcardHasUrl ?? this.foafHomepage ?? null - } - - get photoUrl(): string | null { - return OptionalFrom.subjectPredicate(this, VCARD.hasPhoto, LiteralAs.string) ?? null - } - - get pimStorage(): Set { - return SetFrom.subjectPredicate(this, PIM.storage, NamedNodeAs.string, NamedNodeFrom.string) - } - - get solidStorage(): Set { - return SetFrom.subjectPredicate(this, SOLID.storage, NamedNodeAs.string, NamedNodeFrom.string) - } - - get email(): string | null { - return this.hasEmail?.actualValue ?? null - } - - get hasEmail(): HasValue | undefined { - return OptionalFrom.subjectPredicate(this, VCARD.hasEmail, TermAs.instance(HasValue)) - } - - get knows(): Set { - return SetFrom.subjectPredicate(this, FOAF.knows, NamedNodeAs.string, NamedNodeFrom.string) - } -} - -class HasValue extends TermWrapper { - get actualValue(): string { - return this.hasValue ?? this.value - } - - get hasValue(): string | undefined { - return OptionalFrom.subjectPredicate(this, VCARD.hasValue, NamedNodeAs.string) - } -} diff --git a/app/lib/class/Container.ts b/app/lib/class/Container.ts deleted file mode 100644 index e3bf5d4..0000000 --- a/app/lib/class/Container.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { SetFrom, TermAs, TermFrom } from "@rdfjs/wrapper" -import { Resource } from "@/app/lib/class/Resource" -import { LDP } from "@/app/lib/class/Vocabulary" - -export class Container extends Resource { - public get contains(): Set { - return SetFrom.subjectPredicate(this, LDP.contains, TermAs.instance(Resource), TermFrom.instance) - } -} diff --git a/app/lib/class/ContainerDataset.ts b/app/lib/class/ContainerDataset.ts deleted file mode 100644 index 854ca4f..0000000 --- a/app/lib/class/ContainerDataset.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { DatasetWrapper } from "@rdfjs/wrapper" -import { Container } from "@/app/lib/class/Container" -import { LDP } from "@/app/lib/class/Vocabulary" - -export class ContainerDataset extends DatasetWrapper { - // TODO: Consider that this might be undefined if there are no contained resources. We might need different matching. - get container(): Container | undefined { - // Return the first container in the dataset - for (const s of this.subjectsOf(LDP.contains, Container)) { - return s; - } - } -} diff --git a/app/lib/class/Matcher.ts b/app/lib/class/Matcher.ts deleted file mode 100644 index b72c0e7..0000000 --- a/app/lib/class/Matcher.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { NamedNodeAs, NamedNodeFrom, SetFrom } from "@rdfjs/wrapper" -import { ACP } from "@/app/lib/class/Vocabulary" -import { Typed } from "@/app/lib/class/Typed" - -export class Matcher extends Typed { - get agent(): Set { - return SetFrom.subjectPredicate(this, ACP.agent, NamedNodeAs.string, NamedNodeFrom.string) - } -} diff --git a/app/lib/class/Policy.ts b/app/lib/class/Policy.ts deleted file mode 100644 index ff232e4..0000000 --- a/app/lib/class/Policy.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { NamedNodeAs, NamedNodeFrom, SetFrom, TermAs, TermFrom } from "@rdfjs/wrapper" -import { Matcher } from "@/app/lib/class/Matcher" -import { ACP } from "@/app/lib/class/Vocabulary" -import { Typed } from "@/app/lib/class/Typed" - -export class Policy extends Typed { - get allow(): Set { - return SetFrom.subjectPredicate(this, ACP.allow, NamedNodeAs.string, NamedNodeFrom.string) - } - - get anyOf(): Set { - return SetFrom.subjectPredicate(this, ACP.anyOf, TermAs.instance(Matcher), TermFrom.instance) - } -} diff --git a/app/lib/class/Resource.ts b/app/lib/class/Resource.ts deleted file mode 100644 index 09da1e3..0000000 --- a/app/lib/class/Resource.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { LiteralAs, NamedNodeAs, NamedNodeFrom, OptionalFrom, SetFrom, TermWrapper } from "@rdfjs/wrapper" -import { DC, POSIX, RDF, RDFS } from "@/app/lib/class/Vocabulary" -import { extractNameFromUrl, FileType } from "@/app/lib/helpers" - -export class Resource extends TermWrapper { - #ianaMediaTypePattern = /^http:\/\/www\.w3\.org\/ns\/iana\/media-types\/(.+)#Resource$/; - - get id(): string { - return this.value - } - - get isContainer(): boolean { - return this.id.endsWith("/") - } - - get fileType(): FileType { - return this.isContainer ? "folder" : "file" - } - - get title(): string | undefined { - return OptionalFrom.subjectPredicate(this, DC.title, LiteralAs.string) - } - - get label(): string | undefined { - return OptionalFrom.subjectPredicate(this, RDFS.label, LiteralAs.string) - } - - get name(): string { - return this.title ?? this.label ?? extractNameFromUrl(this.id) - } - - get modified(): Date | undefined { - return OptionalFrom.subjectPredicate(this, DC.modified, LiteralAs.date) - } - - get mtime(): Date | undefined { - return OptionalFrom.subjectPredicate(this, POSIX.mtime, LiteralAs.date) - } - - get lastModified(): Date | undefined { - return this.modified ?? this.mtime - } - - get size(): number | undefined { - return OptionalFrom.subjectPredicate(this, POSIX.size, LiteralAs.number) - } - - get type(): Set { - return SetFrom.subjectPredicate(this, RDF.type, NamedNodeAs.string, NamedNodeFrom.string) - } - - get mimeType(): string | undefined { - const matches = [...this.type] - .map(t => this.#ianaMediaTypePattern.exec(t)) - .filter(results => results !== null) - .map(results => results[0]) - - for (const match of matches) { - return match - } - } - - toString() { - return this.id - } -} diff --git a/app/lib/class/Typed.ts b/app/lib/class/Typed.ts deleted file mode 100644 index 7855fed..0000000 --- a/app/lib/class/Typed.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { NamedNodeAs, NamedNodeFrom, SetFrom, TermWrapper } from "@rdfjs/wrapper" -import { RDF } from "@/app/lib/class/Vocabulary" - -export class Typed extends TermWrapper { - get type(): Set { - return SetFrom.subjectPredicate(this, RDF.type, NamedNodeAs.string, NamedNodeFrom.string) - } -} diff --git a/app/lib/class/Vocabulary.ts b/app/lib/class/Vocabulary.ts deleted file mode 100644 index 9e2df10..0000000 --- a/app/lib/class/Vocabulary.ts +++ /dev/null @@ -1,66 +0,0 @@ -export const ACP = { - resource: "http://www.w3.org/ns/solid/acp#resource", - accessControl: "http://www.w3.org/ns/solid/acp#accessControl", - memberAccessControl: "http://www.w3.org/ns/solid/acp#memberAccessControl", - AccessControlResource: "http://www.w3.org/ns/solid/acp#AccessControlResource", - apply: "http://www.w3.org/ns/solid/acp#apply", - anyOf: "http://www.w3.org/ns/solid/acp#anyOf", - agent: "http://www.w3.org/ns/solid/acp#agent", - Matcher: "http://www.w3.org/ns/solid/acp#Matcher", - Policy: "http://www.w3.org/ns/solid/acp#Policy", - allow: "http://www.w3.org/ns/solid/acp#allow", - mode: "http://www.w3.org/ns/solid/acp#mode", - AccessControl: "http://www.w3.org/ns/solid/acp#AccessControl", -} as const - -export const DC = { - modified: "http://purl.org/dc/terms/modified", - title: "http://purl.org/dc/terms/title", -} as const - -export const FOAF = { - isPrimaryTopicOf: "http://xmlns.com/foaf/0.1/isPrimaryTopicOf", - primaryTopic: "http://xmlns.com/foaf/0.1/primaryTopic", - fname: "http://xmlns.com/foaf/0.1/name", - email: "http://xmlns.com/foaf/0.1/email", - homepage: "http://xmlns.com/foaf/0.1/homepage", - knows: "http://xmlns.com/foaf/0.1/knows", -} as const - -export const LDP = { - contains: "http://www.w3.org/ns/ldp#contains", -} as const - -export const PIM = { - storage: "http://www.w3.org/ns/pim/space#storage", -} as const - -export const POSIX = { - size: "http://www.w3.org/ns/posix/stat#size", - mtime: "http://www.w3.org/ns/posix/stat#mtime", -} as const - -export const RDF = { - type: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", -} as const - -export const RDFS = { - label: "http://www.w3.org/2000/01/rdf-schema#label", -} as const - -export const SOLID = { - oidcIssuer: "http://www.w3.org/ns/solid/terms#oidcIssuer", - storage: "http://www.w3.org/ns/solid/terms#storage", -} as const - -export const VCARD = { - fn: "http://www.w3.org/2006/vcard/ns#fn", - hasEmail: "http://www.w3.org/2006/vcard/ns#hasEmail", - hasValue: "http://www.w3.org/2006/vcard/ns#hasValue", - hasPhoto: "http://www.w3.org/2006/vcard/ns#hasPhoto", - hasTelephone: "http://www.w3.org/2006/vcard/ns#hasTelephone", - title: "http://www.w3.org/2006/vcard/ns#title", - hasUrl: "http://www.w3.org/2006/vcard/ns#hasUrl", - organizationName: "http://www.w3.org/2006/vcard/ns#organization-name", - role: "http://www.w3.org/2006/vcard/ns#organization-name", -} as const diff --git a/app/lib/class/WebIdDataset.ts b/app/lib/class/WebIdDataset.ts deleted file mode 100644 index 36308df..0000000 --- a/app/lib/class/WebIdDataset.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { DatasetWrapper } from "@rdfjs/wrapper" -import { Agent } from "@/app/lib/class/Agent" -import { SOLID } from "@/app/lib/class/Vocabulary" - -export class WebIdDataset extends DatasetWrapper { - get mainSubject(): Agent | undefined { - // TODO: Fix with FOAF: Primary topic either via Inrupt or spec because this does not work with Inrupt WebID - // TODO: do the isPrimaryTopicOf route and the primaryTopic (maybe) - // Or not because all WebIDs will have an issuer (otherwise also needs to restrict to the document URL as subject or object to realise the benefit) - for (const s of this.subjectsOf(SOLID.oidcIssuer, Agent)) { - return s; - } - } -} diff --git a/app/lib/helpers/acpUtils.ts b/app/lib/helpers/acpUtils.ts index 9f0d189..8762630 100644 --- a/app/lib/helpers/acpUtils.ts +++ b/app/lib/helpers/acpUtils.ts @@ -9,13 +9,15 @@ */ import { getAuthenticatedSession } from "./sessionUtils"; -import { AcrDataset } from "@/app/lib/class/AcrDataset"; import type { DatasetCore } from "@rdfjs/types"; -import { AccessControlResource } from "@/app/lib/class/AccessControlResource"; -import { ACP } from "@/app/lib/class/Vocabulary"; -import { Matcher } from "@/app/lib/class/Matcher"; -import { Policy } from "@/app/lib/class/Policy"; -import { AccessControl } from "@/app/lib/class/AccessControl"; +import { + AcrDataset, + AccessControlResource, + AccessControl, + Matcher, + Policy, +} from "@solid/object/acp"; +import { ACP } from "@solid/object/vocabulary"; import { DataFactory, Parser, Store, Writer } from "n3"; import { getHttpStatus } from "./httpErrorUtils"; diff --git a/app/lib/helpers/profileUtils.ts b/app/lib/helpers/profileUtils.ts index e0863be..d352b83 100644 --- a/app/lib/helpers/profileUtils.ts +++ b/app/lib/helpers/profileUtils.ts @@ -1,7 +1,6 @@ import { Parser, Store, DataFactory } from "n3"; import { getSession } from "./sessionUtils"; -import { WebIdDataset } from "@/app/lib/class/WebIdDataset"; -import type { Agent } from "@/app/lib/class/Agent"; +import { WebIdDataset, type Agent } from "@solid/object/webid"; // Cache for parsed profile documents const profileCache = new Map(); diff --git a/app/lib/hooks/useBrowseStorage.ts b/app/lib/hooks/useBrowseStorage.ts index f507317..e53702f 100644 --- a/app/lib/hooks/useBrowseStorage.ts +++ b/app/lib/hooks/useBrowseStorage.ts @@ -4,7 +4,7 @@ import { useEffect, useState } from "react"; import { getAuthenticatedSession } from "../helpers"; import { getSolidDataset, toRdfJsDataset } from "@inrupt/solid-client"; import { FileItemData } from "../../components/FileItem"; -import { ContainerDataset } from "../class/ContainerDataset"; +import { ContainerDataset } from "@solid/object/solid"; import { DataFactory } from "n3"; interface UseBrowseStorageResult { diff --git a/package-lock.json b/package-lock.json index 1c3e287..8d691b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@inrupt/solid-client": "^1.23.1", "@inrupt/solid-client-authn-browser": "^3.1.1", "@ldo/solid-react": "^1.0.0-alpha.33", - "@rdfjs/wrapper": "^0.33.0", + "@solid/object": "^0.8.0", "jszip": "^3.10.1", "n3": "^2.0.1", "next": "16.0.7", @@ -7549,15 +7549,6 @@ "@types/node": "*" } }, - "node_modules/@rdfjs/wrapper": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@rdfjs/wrapper/-/wrapper-0.33.0.tgz", - "integrity": "sha512-jnSWcy58pXfhbdKtwSilsjKDN1tdXzSDUEgGPAXc9Jp7JFqr1U1i0GcI5b9JKgyolZbFhwdnesWoPiIlALaMLQ==", - "license": "MIT", - "engines": { - "node": ">=24.0.0" - } - }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -7818,6 +7809,27 @@ "url": "https://github.com/sponsors/rubensworks/" } }, + "node_modules/@solid/object": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@solid/object/-/object-0.8.0.tgz", + "integrity": "sha512-PFPPgxe/BXrvkpzt5YJVMzx4zVKqEA2QhybFu1Vz/i9qENoG13O4yqOLCSebeYp+0LzJ3zamjJMWqb97fmHG2Q==", + "license": "MIT", + "dependencies": { + "@rdfjs/wrapper": "^0.34.0" + }, + "engines": { + "node": ">=24.0.0" + } + }, + "node_modules/@solid/object/node_modules/@rdfjs/wrapper": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@rdfjs/wrapper/-/wrapper-0.34.0.tgz", + "integrity": "sha512-psGw4IAH0E27P7Nlro0SzjqPJJ+aE3MkYKWfNbBk+vwT2Zt+gJJyuznuYg54peZs4rAF9FLoqCe4JdvQNDTzMw==", + "license": "MIT", + "engines": { + "node": ">=24.0.0" + } + }, "node_modules/@solidlab/policy-engine": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/@solidlab/policy-engine/-/policy-engine-0.0.2.tgz", diff --git a/package.json b/package.json index cf94c34..ac371ab 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "@inrupt/solid-client": "^1.23.1", "@inrupt/solid-client-authn-browser": "^3.1.1", "@ldo/solid-react": "^1.0.0-alpha.33", - "@rdfjs/wrapper": "^0.33.0", + "@solid/object": "^0.8.0", "jszip": "^3.10.1", "n3": "^2.0.1", "next": "16.0.7",