From 453ee230f31eb4f1b707f7be8d72fb5ed069b353 Mon Sep 17 00:00:00 2001 From: Jackson Morgan Date: Thu, 20 Mar 2025 14:53:13 -0400 Subject: [PATCH] Wac and requester refactor --- .../connected-solid/src/.ldo/solid.context.ts | 108 ++++++++ .../connected-solid/src/.ldo/solid.schema.ts | 233 ++++++++++++++++++ .../src/.ldo/solid.shapeTypes.ts | 37 +++ .../connected-solid/src/.ldo/solid.typings.ts | 84 +++++++ .../connected-solid/src/.ldo/wac.context.ts | 78 ++++++ .../connected-solid/src/.ldo/wac.schema.ts | 169 +++++++++++++ .../src/.ldo/wac.shapeTypes.ts | 19 ++ .../connected-solid/src/.ldo/wac.typings.ts | 73 ++++++ .../connected-solid/src/.shapes/solid.shex | 43 ++++ packages/connected-solid/src/.shapes/wac.shex | 23 ++ .../src/SolidConnectedPlugin.ts | 4 +- .../requester/requests/createDataResource.ts | 18 +- .../src/requester/requests/readResource.ts | 22 +- .../results/error/HttpErrorResult.ts | 2 +- .../requester/results/success/ReadSuccess.ts | 2 +- .../src/resources/SolidResource.ts | 49 ++-- packages/connected-solid/src/test.ts | 19 -- packages/connected-solid/src/util/rdfUtils.ts | 32 +-- .../connected-solid/src/wac/getWacRule.ts | 81 +++--- packages/connected-solid/src/wac/getWacUri.ts | 56 ++--- .../src/wac/results/GetWacRuleSuccess.ts | 15 +- .../src/wac/results/GetWacUriSuccess.ts | 19 +- .../src/wac/results/SetWacRuleSuccess.ts | 15 +- .../src/wac/results/WacRuleAbsent.ts | 10 +- .../connected-solid/src/wac/setWacRule.ts | 70 ++++-- 25 files changed, 1112 insertions(+), 169 deletions(-) create mode 100644 packages/connected-solid/src/.ldo/solid.context.ts create mode 100644 packages/connected-solid/src/.ldo/solid.schema.ts create mode 100644 packages/connected-solid/src/.ldo/solid.shapeTypes.ts create mode 100644 packages/connected-solid/src/.ldo/solid.typings.ts create mode 100644 packages/connected-solid/src/.ldo/wac.context.ts create mode 100644 packages/connected-solid/src/.ldo/wac.schema.ts create mode 100644 packages/connected-solid/src/.ldo/wac.shapeTypes.ts create mode 100644 packages/connected-solid/src/.ldo/wac.typings.ts create mode 100644 packages/connected-solid/src/.shapes/solid.shex create mode 100644 packages/connected-solid/src/.shapes/wac.shex delete mode 100644 packages/connected-solid/src/test.ts diff --git a/packages/connected-solid/src/.ldo/solid.context.ts b/packages/connected-solid/src/.ldo/solid.context.ts new file mode 100644 index 0000000..7f50b27 --- /dev/null +++ b/packages/connected-solid/src/.ldo/solid.context.ts @@ -0,0 +1,108 @@ +import { LdoJsonldContext } from "@ldo/ldo"; + +/** + * ============================================================================= + * solidContext: JSONLD Context for solid + * ============================================================================= + */ +export const solidContext: LdoJsonldContext = { + type: { + "@id": "@type", + "@isCollection": true, + }, + Container: { + "@id": "http://www.w3.org/ns/ldp#Container", + "@context": { + type: { + "@id": "@type", + "@isCollection": true, + }, + modified: { + "@id": "http://purl.org/dc/terms/modified", + "@type": "http://www.w3.org/2001/XMLSchema#string", + }, + contains: { + "@id": "http://www.w3.org/ns/ldp#contains", + "@type": "@id", + "@isCollection": true, + }, + mtime: { + "@id": "http://www.w3.org/ns/posix/stat#mtime", + "@type": "http://www.w3.org/2001/XMLSchema#decimal", + }, + size: { + "@id": "http://www.w3.org/ns/posix/stat#size", + "@type": "http://www.w3.org/2001/XMLSchema#integer", + }, + }, + }, + Resource: { + "@id": "http://www.w3.org/ns/ldp#Resource", + "@context": { + type: { + "@id": "@type", + "@isCollection": true, + }, + modified: { + "@id": "http://purl.org/dc/terms/modified", + "@type": "http://www.w3.org/2001/XMLSchema#string", + }, + contains: { + "@id": "http://www.w3.org/ns/ldp#contains", + "@type": "@id", + "@isCollection": true, + }, + mtime: { + "@id": "http://www.w3.org/ns/posix/stat#mtime", + "@type": "http://www.w3.org/2001/XMLSchema#decimal", + }, + size: { + "@id": "http://www.w3.org/ns/posix/stat#size", + "@type": "http://www.w3.org/2001/XMLSchema#integer", + }, + }, + }, + modified: { + "@id": "http://purl.org/dc/terms/modified", + "@type": "http://www.w3.org/2001/XMLSchema#string", + }, + contains: { + "@id": "http://www.w3.org/ns/ldp#contains", + "@type": "@id", + "@isCollection": true, + }, + Resource2: { + "@id": "http://www.w3.org/ns/iana/media-types/text/turtle#Resource", + "@context": { + type: { + "@id": "@type", + "@isCollection": true, + }, + modified: { + "@id": "http://purl.org/dc/terms/modified", + "@type": "http://www.w3.org/2001/XMLSchema#string", + }, + mtime: { + "@id": "http://www.w3.org/ns/posix/stat#mtime", + "@type": "http://www.w3.org/2001/XMLSchema#decimal", + }, + size: { + "@id": "http://www.w3.org/ns/posix/stat#size", + "@type": "http://www.w3.org/2001/XMLSchema#integer", + }, + }, + }, + mtime: { + "@id": "http://www.w3.org/ns/posix/stat#mtime", + "@type": "http://www.w3.org/2001/XMLSchema#decimal", + }, + size: { + "@id": "http://www.w3.org/ns/posix/stat#size", + "@type": "http://www.w3.org/2001/XMLSchema#integer", + }, + storage: { + "@id": "http://www.w3.org/ns/pim/space#storage", + "@type": "@id", + "@isCollection": true, + }, +}; diff --git a/packages/connected-solid/src/.ldo/solid.schema.ts b/packages/connected-solid/src/.ldo/solid.schema.ts new file mode 100644 index 0000000..4d9adc0 --- /dev/null +++ b/packages/connected-solid/src/.ldo/solid.schema.ts @@ -0,0 +1,233 @@ +import { Schema } from "shexj"; + +/** + * ============================================================================= + * solidSchema: ShexJ Schema for solid + * ============================================================================= + */ +export const solidSchema: Schema = { + type: "Schema", + shapes: [ + { + id: "http://www.w3.org/ns/lddps#Container", + type: "ShapeDecl", + shapeExpr: { + type: "Shape", + expression: { + id: "http://www.w3.org/ns/lddps#ContainerShape", + type: "EachOf", + expressions: [ + { + type: "TripleConstraint", + predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", + valueExpr: { + type: "NodeConstraint", + values: [ + "http://www.w3.org/ns/ldp#Container", + "http://www.w3.org/ns/ldp#Resource", + ], + }, + min: 0, + max: -1, + annotations: [ + { + type: "Annotation", + predicate: "http://www.w3.org/2000/01/rdf-schema#comment", + object: { + value: "A container on a Solid server", + }, + }, + ], + }, + { + type: "TripleConstraint", + predicate: "http://purl.org/dc/terms/modified", + valueExpr: { + type: "NodeConstraint", + datatype: "http://www.w3.org/2001/XMLSchema#string", + }, + min: 0, + max: 1, + annotations: [ + { + type: "Annotation", + predicate: "http://www.w3.org/2000/01/rdf-schema#comment", + object: { + value: "Date modified", + }, + }, + ], + }, + { + type: "TripleConstraint", + predicate: "http://www.w3.org/ns/ldp#contains", + valueExpr: "http://www.w3.org/ns/lddps#Resource", + min: 0, + max: -1, + annotations: [ + { + type: "Annotation", + predicate: "http://www.w3.org/2000/01/rdf-schema#comment", + object: { + value: "Defines a Solid Resource", + }, + }, + ], + }, + { + type: "TripleConstraint", + predicate: "http://www.w3.org/ns/posix/stat#mtime", + valueExpr: { + type: "NodeConstraint", + datatype: "http://www.w3.org/2001/XMLSchema#decimal", + }, + min: 0, + max: 1, + annotations: [ + { + type: "Annotation", + predicate: "http://www.w3.org/2000/01/rdf-schema#comment", + object: { + value: "?", + }, + }, + ], + }, + { + type: "TripleConstraint", + predicate: "http://www.w3.org/ns/posix/stat#size", + valueExpr: { + type: "NodeConstraint", + datatype: "http://www.w3.org/2001/XMLSchema#integer", + }, + min: 0, + max: 1, + annotations: [ + { + type: "Annotation", + predicate: "http://www.w3.org/2000/01/rdf-schema#comment", + object: { + value: "size of this container", + }, + }, + ], + }, + ], + }, + extra: ["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"], + }, + }, + { + id: "http://www.w3.org/ns/lddps#Resource", + type: "ShapeDecl", + shapeExpr: { + type: "Shape", + expression: { + id: "http://www.w3.org/ns/lddps#ResourceShape", + type: "EachOf", + expressions: [ + { + type: "TripleConstraint", + predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", + valueExpr: { + type: "NodeConstraint", + values: [ + "http://www.w3.org/ns/ldp#Resource", + "http://www.w3.org/ns/iana/media-types/text/turtle#Resource", + ], + }, + min: 0, + max: -1, + annotations: [ + { + type: "Annotation", + predicate: "http://www.w3.org/2000/01/rdf-schema#comment", + object: { + value: "Any resource on a Solid server", + }, + }, + ], + }, + { + type: "TripleConstraint", + predicate: "http://purl.org/dc/terms/modified", + valueExpr: { + type: "NodeConstraint", + datatype: "http://www.w3.org/2001/XMLSchema#string", + }, + min: 0, + max: 1, + annotations: [ + { + type: "Annotation", + predicate: "http://www.w3.org/2000/01/rdf-schema#comment", + object: { + value: "Date modified", + }, + }, + ], + }, + { + type: "TripleConstraint", + predicate: "http://www.w3.org/ns/posix/stat#mtime", + valueExpr: { + type: "NodeConstraint", + datatype: "http://www.w3.org/2001/XMLSchema#decimal", + }, + min: 0, + max: 1, + annotations: [ + { + type: "Annotation", + predicate: "http://www.w3.org/2000/01/rdf-schema#comment", + object: { + value: "?", + }, + }, + ], + }, + { + type: "TripleConstraint", + predicate: "http://www.w3.org/ns/posix/stat#size", + valueExpr: { + type: "NodeConstraint", + datatype: "http://www.w3.org/2001/XMLSchema#integer", + }, + min: 0, + max: 1, + annotations: [ + { + type: "Annotation", + predicate: "http://www.w3.org/2000/01/rdf-schema#comment", + object: { + value: "size of this container", + }, + }, + ], + }, + ], + }, + extra: ["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"], + }, + }, + { + id: "http://www.w3.org/ns/lddps#ProfileWithStorage", + type: "ShapeDecl", + shapeExpr: { + type: "Shape", + expression: { + id: "http://www.w3.org/ns/lddps#ProfileWithStorageShape", + type: "TripleConstraint", + predicate: "http://www.w3.org/ns/pim/space#storage", + valueExpr: { + type: "NodeConstraint", + nodeKind: "iri", + }, + min: 0, + max: -1, + }, + extra: ["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"], + }, + }, + ], +}; diff --git a/packages/connected-solid/src/.ldo/solid.shapeTypes.ts b/packages/connected-solid/src/.ldo/solid.shapeTypes.ts new file mode 100644 index 0000000..69ddd90 --- /dev/null +++ b/packages/connected-solid/src/.ldo/solid.shapeTypes.ts @@ -0,0 +1,37 @@ +import { ShapeType } from "@ldo/ldo"; +import { solidSchema } from "./solid.schema"; +import { solidContext } from "./solid.context"; +import { Container, Resource, ProfileWithStorage } from "./solid.typings"; + +/** + * ============================================================================= + * LDO ShapeTypes solid + * ============================================================================= + */ + +/** + * Container ShapeType + */ +export const ContainerShapeType: ShapeType = { + schema: solidSchema, + shape: "http://www.w3.org/ns/lddps#Container", + context: solidContext, +}; + +/** + * Resource ShapeType + */ +export const ResourceShapeType: ShapeType = { + schema: solidSchema, + shape: "http://www.w3.org/ns/lddps#Resource", + context: solidContext, +}; + +/** + * ProfileWithStorage ShapeType + */ +export const ProfileWithStorageShapeType: ShapeType = { + schema: solidSchema, + shape: "http://www.w3.org/ns/lddps#ProfileWithStorage", + context: solidContext, +}; diff --git a/packages/connected-solid/src/.ldo/solid.typings.ts b/packages/connected-solid/src/.ldo/solid.typings.ts new file mode 100644 index 0000000..0405e75 --- /dev/null +++ b/packages/connected-solid/src/.ldo/solid.typings.ts @@ -0,0 +1,84 @@ +import { LdoJsonldContext, LdSet } from "@ldo/ldo"; + +/** + * ============================================================================= + * Typescript Typings for solid + * ============================================================================= + */ + +/** + * Container Type + */ +export interface Container { + "@id"?: string; + "@context"?: LdoJsonldContext; + /** + * A container on a Solid server + */ + type?: LdSet< + | { + "@id": "Container"; + } + | { + "@id": "Resource"; + } + >; + /** + * Date modified + */ + modified?: string; + /** + * Defines a Solid Resource + */ + contains?: LdSet; + /** + * ? + */ + mtime?: number; + /** + * size of this container + */ + size?: number; +} + +/** + * Resource Type + */ +export interface Resource { + "@id"?: string; + "@context"?: LdoJsonldContext; + /** + * Any resource on a Solid server + */ + type?: LdSet< + | { + "@id": "Resource"; + } + | { + "@id": "Resource2"; + } + >; + /** + * Date modified + */ + modified?: string; + /** + * ? + */ + mtime?: number; + /** + * size of this container + */ + size?: number; +} + +/** + * ProfileWithStorage Type + */ +export interface ProfileWithStorage { + "@id"?: string; + "@context"?: LdoJsonldContext; + storage?: LdSet<{ + "@id": string; + }>; +} diff --git a/packages/connected-solid/src/.ldo/wac.context.ts b/packages/connected-solid/src/.ldo/wac.context.ts new file mode 100644 index 0000000..6f6c9fd --- /dev/null +++ b/packages/connected-solid/src/.ldo/wac.context.ts @@ -0,0 +1,78 @@ +import { LdoJsonldContext } from "@ldo/ldo"; + +/** + * ============================================================================= + * wacContext: JSONLD Context for wac + * ============================================================================= + */ +export const wacContext: LdoJsonldContext = { + type: { + "@id": "@type", + }, + Authorization: { + "@id": "http://www.w3.org/ns/auth/acl#Authorization", + "@context": { + type: { + "@id": "@type", + }, + accessTo: { + "@id": "http://www.w3.org/ns/auth/acl#accessTo", + "@type": "@id", + }, + default: { + "@id": "http://www.w3.org/ns/auth/acl#default", + "@type": "@id", + }, + agent: { + "@id": "http://www.w3.org/ns/auth/acl#agent", + "@type": "@id", + "@isCollection": true, + }, + agentGroup: { + "@id": "http://www.w3.org/ns/auth/acl#agentGroup", + "@type": "@id", + "@isCollection": true, + }, + agentClass: { + "@id": "http://www.w3.org/ns/auth/acl#agentClass", + "@isCollection": true, + }, + mode: { + "@id": "http://www.w3.org/ns/auth/acl#mode", + "@isCollection": true, + }, + }, + }, + accessTo: { + "@id": "http://www.w3.org/ns/auth/acl#accessTo", + "@type": "@id", + }, + default: { + "@id": "http://www.w3.org/ns/auth/acl#default", + "@type": "@id", + }, + agent: { + "@id": "http://www.w3.org/ns/auth/acl#agent", + "@type": "@id", + "@isCollection": true, + }, + agentGroup: { + "@id": "http://www.w3.org/ns/auth/acl#agentGroup", + "@type": "@id", + "@isCollection": true, + }, + agentClass: { + "@id": "http://www.w3.org/ns/auth/acl#agentClass", + "@isCollection": true, + }, + AuthenticatedAgent: "http://www.w3.org/ns/auth/acl#AuthenticatedAgent", + Agent: "http://xmlns.com/foaf/0.1/Agent", + mode: { + "@id": "http://www.w3.org/ns/auth/acl#mode", + "@isCollection": true, + }, + Read: "http://www.w3.org/ns/auth/acl#Read", + Write: "http://www.w3.org/ns/auth/acl#Write", + Append: "http://www.w3.org/ns/auth/acl#Append", + Control: "http://www.w3.org/ns/auth/acl#Control", +}; diff --git a/packages/connected-solid/src/.ldo/wac.schema.ts b/packages/connected-solid/src/.ldo/wac.schema.ts new file mode 100644 index 0000000..2d54115 --- /dev/null +++ b/packages/connected-solid/src/.ldo/wac.schema.ts @@ -0,0 +1,169 @@ +import { Schema } from "shexj"; + +/** + * ============================================================================= + * wacSchema: ShexJ Schema for wac + * ============================================================================= + */ +export const wacSchema: Schema = { + type: "Schema", + shapes: [ + { + id: "http://www.w3.org/ns/auth/acls#Authorization", + type: "ShapeDecl", + shapeExpr: { + type: "Shape", + expression: { + id: "http://www.w3.org/ns/auth/acls#AuthorizationShape", + type: "EachOf", + expressions: [ + { + type: "TripleConstraint", + predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", + valueExpr: { + type: "NodeConstraint", + values: ["http://www.w3.org/ns/auth/acl#Authorization"], + }, + annotations: [ + { + type: "Annotation", + predicate: "http://www.w3.org/2000/01/rdf-schema#comment", + object: { + value: "Denotes this as an acl:Authorization", + }, + }, + ], + }, + { + type: "TripleConstraint", + predicate: "http://www.w3.org/ns/auth/acl#accessTo", + valueExpr: { + type: "NodeConstraint", + nodeKind: "iri", + }, + min: 0, + max: 1, + annotations: [ + { + type: "Annotation", + predicate: "http://www.w3.org/2000/01/rdf-schema#comment", + object: { + value: "The subject of this authorization", + }, + }, + ], + }, + { + type: "TripleConstraint", + predicate: "http://www.w3.org/ns/auth/acl#default", + valueExpr: { + type: "NodeConstraint", + nodeKind: "iri", + }, + min: 0, + max: 1, + annotations: [ + { + type: "Annotation", + predicate: "http://www.w3.org/2000/01/rdf-schema#comment", + object: { + value: "The container subject of this authorization", + }, + }, + ], + }, + { + type: "TripleConstraint", + predicate: "http://www.w3.org/ns/auth/acl#agent", + valueExpr: { + type: "NodeConstraint", + nodeKind: "iri", + }, + min: 0, + max: -1, + annotations: [ + { + type: "Annotation", + predicate: "http://www.w3.org/2000/01/rdf-schema#comment", + object: { + value: + "An agent is a person, social entity or software identified by a URI, e.g., a WebID denotes an agent", + }, + }, + ], + }, + { + type: "TripleConstraint", + predicate: "http://www.w3.org/ns/auth/acl#agentGroup", + valueExpr: { + type: "NodeConstraint", + nodeKind: "iri", + }, + min: 0, + max: -1, + annotations: [ + { + type: "Annotation", + predicate: "http://www.w3.org/2000/01/rdf-schema#comment", + object: { + value: + "Denotes a group of agents being given the access permission", + }, + }, + ], + }, + { + type: "TripleConstraint", + predicate: "http://www.w3.org/ns/auth/acl#agentClass", + valueExpr: { + type: "NodeConstraint", + values: [ + "http://www.w3.org/ns/auth/acl#AuthenticatedAgent", + "http://xmlns.com/foaf/0.1/Agent", + ], + }, + min: 0, + max: -1, + annotations: [ + { + type: "Annotation", + predicate: "http://www.w3.org/2000/01/rdf-schema#comment", + object: { + value: + "An agent class is a class of persons or entities identified by a URI.", + }, + }, + ], + }, + { + type: "TripleConstraint", + predicate: "http://www.w3.org/ns/auth/acl#mode", + valueExpr: { + type: "NodeConstraint", + values: [ + "http://www.w3.org/ns/auth/acl#Read", + "http://www.w3.org/ns/auth/acl#Write", + "http://www.w3.org/ns/auth/acl#Append", + "http://www.w3.org/ns/auth/acl#Control", + ], + }, + min: 0, + max: -1, + annotations: [ + { + type: "Annotation", + predicate: "http://www.w3.org/2000/01/rdf-schema#comment", + object: { + value: + "Denotes a class of operations that the agents can perform on a resource.", + }, + }, + ], + }, + ], + }, + extra: ["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"], + }, + }, + ], +}; diff --git a/packages/connected-solid/src/.ldo/wac.shapeTypes.ts b/packages/connected-solid/src/.ldo/wac.shapeTypes.ts new file mode 100644 index 0000000..6689590 --- /dev/null +++ b/packages/connected-solid/src/.ldo/wac.shapeTypes.ts @@ -0,0 +1,19 @@ +import { ShapeType } from "@ldo/ldo"; +import { wacSchema } from "./wac.schema"; +import { wacContext } from "./wac.context"; +import { Authorization } from "./wac.typings"; + +/** + * ============================================================================= + * LDO ShapeTypes wac + * ============================================================================= + */ + +/** + * Authorization ShapeType + */ +export const AuthorizationShapeType: ShapeType = { + schema: wacSchema, + shape: "http://www.w3.org/ns/auth/acls#Authorization", + context: wacContext, +}; diff --git a/packages/connected-solid/src/.ldo/wac.typings.ts b/packages/connected-solid/src/.ldo/wac.typings.ts new file mode 100644 index 0000000..40860e0 --- /dev/null +++ b/packages/connected-solid/src/.ldo/wac.typings.ts @@ -0,0 +1,73 @@ +import { LdoJsonldContext, LdSet } from "@ldo/ldo"; + +/** + * ============================================================================= + * Typescript Typings for wac + * ============================================================================= + */ + +/** + * Authorization Type + */ +export interface Authorization { + "@id"?: string; + "@context"?: LdoJsonldContext; + /** + * Denotes this as an acl:Authorization + */ + type: { + "@id": "Authorization"; + }; + /** + * The subject of this authorization + */ + accessTo?: { + "@id": string; + }; + /** + * The container subject of this authorization + */ + default?: { + "@id": string; + }; + /** + * An agent is a person, social entity or software identified by a URI, e.g., a WebID denotes an agent + */ + agent?: LdSet<{ + "@id": string; + }>; + /** + * Denotes a group of agents being given the access permission + */ + agentGroup?: LdSet<{ + "@id": string; + }>; + /** + * An agent class is a class of persons or entities identified by a URI. + */ + agentClass?: LdSet< + | { + "@id": "AuthenticatedAgent"; + } + | { + "@id": "Agent"; + } + >; + /** + * Denotes a class of operations that the agents can perform on a resource. + */ + mode?: LdSet< + | { + "@id": "Read"; + } + | { + "@id": "Write"; + } + | { + "@id": "Append"; + } + | { + "@id": "Control"; + } + >; +} diff --git a/packages/connected-solid/src/.shapes/solid.shex b/packages/connected-solid/src/.shapes/solid.shex new file mode 100644 index 0000000..f90f1b5 --- /dev/null +++ b/packages/connected-solid/src/.shapes/solid.shex @@ -0,0 +1,43 @@ +PREFIX xsd: +PREFIX rdf: +PREFIX rdfs: +PREFIX ldp: +PREFIX ldps: +PREFIX dct: +PREFIX stat: +PREFIX tur: +PREFIX pim: + +ldps:Container EXTRA a { + $ldps:ContainerShape ( + a [ ldp:Container ldp:Resource ]* + // rdfs:comment "A container on a Solid server"; + dct:modified xsd:string? + // rdfs:comment "Date modified"; + ldp:contains @ldps:Resource* + // rdfs:comment "Defines a Solid Resource"; + stat:mtime xsd:decimal? + // rdfs:comment "?"; + stat:size xsd:integer? + // rdfs:comment "size of this container"; + ) +} + +ldps:Resource EXTRA a { + $ldps:ResourceShape ( + a [ ldp:Resource tur:Resource ]* + // rdfs:comment "Any resource on a Solid server"; + dct:modified xsd:string? + // rdfs:comment "Date modified"; + stat:mtime xsd:decimal? + // rdfs:comment "?"; + stat:size xsd:integer? + // rdfs:comment "size of this container"; + ) +} + +ldps:ProfileWithStorage EXTRA a { + $ldps:ProfileWithStorageShape ( + pim:storage IRI *; + ) +} diff --git a/packages/connected-solid/src/.shapes/wac.shex b/packages/connected-solid/src/.shapes/wac.shex new file mode 100644 index 0000000..5ff19cd --- /dev/null +++ b/packages/connected-solid/src/.shapes/wac.shex @@ -0,0 +1,23 @@ +PREFIX acl: +PREFIX acls: +PREFIX foaf: +PREFIX rdfs: + +acls:Authorization EXTRA a { + $acls:AuthorizationShape ( + a [ acl:Authorization ] + // rdfs:comment "Denotes this as an acl:Authorization"; + acl:accessTo IRI? + // rdfs:comment "The subject of this authorization"; + acl:default IRI? + // rdfs:comment "The container subject of this authorization"; + acl:agent IRI* + // rdfs:comment "An agent is a person, social entity or software identified by a URI, e.g., a WebID denotes an agent"; + acl:agentGroup IRI* + // rdfs:comment "Denotes a group of agents being given the access permission"; + acl:agentClass [ acl:AuthenticatedAgent foaf:Agent ]* + // rdfs:comment "An agent class is a class of persons or entities identified by a URI."; + acl:mode [ acl:Read acl:Write acl:Append acl:Control ]* + // rdfs:comment "Denotes a class of operations that the agents can perform on a resource."; + ) +} diff --git a/packages/connected-solid/src/SolidConnectedPlugin.ts b/packages/connected-solid/src/SolidConnectedPlugin.ts index 91af9db..4f59ad7 100644 --- a/packages/connected-solid/src/SolidConnectedPlugin.ts +++ b/packages/connected-solid/src/SolidConnectedPlugin.ts @@ -27,12 +27,14 @@ export interface SolidConnectedPlugin export const solidConnectedPlugin: SolidConnectedPlugin = { name: "solid", + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore This functions when its user-facing getResource: function ( uri: SolidLeafUri | SolidContainerUri, context: ConnectedContext, ): SolidLeaf | SolidContainer { if (isSolidContainerUri(uri)) { - return new SolidContainer(uri, context.solid); + return new SolidContainer(uri, context); } else { return new SolidLeaf(uri, context); } diff --git a/packages/connected-solid/src/requester/requests/createDataResource.ts b/packages/connected-solid/src/requester/requests/createDataResource.ts index 6775188..ac7b1fe 100644 --- a/packages/connected-solid/src/requester/requests/createDataResource.ts +++ b/packages/connected-solid/src/requester/requests/createDataResource.ts @@ -206,7 +206,10 @@ export async function createDataResource( if (overwrite) { const deleteResult = await deleteResource(resource, options); // Return if it wasn't deleted - if (deleteResult.isError) return deleteResult; + if (deleteResult.isError) + return deleteResult as + | DeleteResultError + | DeleteResultError; didOverwrite = deleteResult.resourceExisted; } else { // Perform a read to check if it exists @@ -232,13 +235,20 @@ export async function createDataResource( }); const httpError = HttpErrorResult.checkResponse(resource, response); - if (httpError) return httpError; + if (httpError) + return httpError as + | HttpErrorResultType + | HttpErrorResultType; if (options?.dataset) { addResourceRdfToContainer(resource.uri, options.dataset); } - return new CreateSuccess(resource, didOverwrite); + return new CreateSuccess(resource, didOverwrite) as + | CreateSuccess + | CreateSuccess; } catch (err) { - return UnexpectedResourceError.fromThrown(resource, err); + return UnexpectedResourceError.fromThrown(resource, err) as + | UnexpectedResourceError + | UnexpectedResourceError; } } diff --git a/packages/connected-solid/src/requester/requests/readResource.ts b/packages/connected-solid/src/requester/requests/readResource.ts index 7880dc4..c0558ba 100644 --- a/packages/connected-solid/src/requester/requests/readResource.ts +++ b/packages/connected-solid/src/requester/requests/readResource.ts @@ -115,10 +115,15 @@ export async function readResource( ); } - return new AbsentReadSuccess(resource, false); + return new AbsentReadSuccess(resource, false) as + | AbsentReadSuccess + | AbsentReadSuccess; } const httpErrorResult = HttpErrorResult.checkResponse(resource, response); - if (httpErrorResult) return httpErrorResult; + if (httpErrorResult) + return httpErrorResult as + | HttpErrorResultType + | HttpErrorResultType; // Add this resource to the container if (options?.dataset) { @@ -130,7 +135,9 @@ export async function readResource( return new NoncompliantPodError( resource, "Resource requests must return a content-type header.", - ); + ) as + | NoncompliantPodError + | NoncompliantPodError; } if (contentType.startsWith("text/turtle")) { @@ -142,7 +149,10 @@ export async function readResource( options.dataset, resource.uri, ); - if (result) return result; + if (result) + return new NoncompliantPodError(resource, result.message) as + | NoncompliantPodError + | NoncompliantPodError; } if (resource.type === "container") { const result = checkHeadersForRootContainer(resource, response.headers); @@ -164,6 +174,8 @@ export async function readResource( ); } } catch (err) { - return UnexpectedResourceError.fromThrown(resource, err); + return UnexpectedResourceError.fromThrown(resource, err) as + | UnexpectedResourceError + | UnexpectedResourceError; } } diff --git a/packages/connected-solid/src/requester/results/error/HttpErrorResult.ts b/packages/connected-solid/src/requester/results/error/HttpErrorResult.ts index 3f4df5a..fe9e6e8 100644 --- a/packages/connected-solid/src/requester/results/error/HttpErrorResult.ts +++ b/packages/connected-solid/src/requester/results/error/HttpErrorResult.ts @@ -70,7 +70,7 @@ export abstract class HttpErrorResult< static checkResponse( resource: ResourceType, response: Response, - ) { + ): HttpErrorResultType | undefined { if (ServerHttpError.is(response)) { return new ServerHttpError(resource, response); } diff --git a/packages/connected-solid/src/requester/results/success/ReadSuccess.ts b/packages/connected-solid/src/requester/results/success/ReadSuccess.ts index d76ef04..1af51a9 100644 --- a/packages/connected-solid/src/requester/results/success/ReadSuccess.ts +++ b/packages/connected-solid/src/requester/results/success/ReadSuccess.ts @@ -61,7 +61,7 @@ export class DataReadSuccess extends ReadSuccess { * retrieved was a container resource. */ export class ContainerReadSuccess extends ReadSuccess { - type: "containerReadSuccess"; + type = "containerReadSuccess" as const; /** * True if this container is a root container */ diff --git a/packages/connected-solid/src/resources/SolidResource.ts b/packages/connected-solid/src/resources/SolidResource.ts index 9e62cbc..0c916ae 100644 --- a/packages/connected-solid/src/resources/SolidResource.ts +++ b/packages/connected-solid/src/resources/SolidResource.ts @@ -49,6 +49,8 @@ import { setWacRuleForAclUri } from "../wac/setWacRule"; import { NoncompliantPodError } from "../requester/results/error/NoncompliantPodError"; import type { SolidNotificationMessage } from "../notifications/SolidNotificationMessage"; import type { CreateSuccess } from "../requester/results/success/CreateSuccess"; +import { GetWacUriSuccess } from "../wac/results/GetWacUriSuccess"; +import { GetWacRuleSuccess } from "../wac/results/GetWacRuleSuccess"; /** * Statuses shared between both Leaf and Container @@ -592,18 +594,14 @@ export abstract class SolidResource */ protected async getWacUri(options?: { ignoreCache: boolean; - }): Promise { + }): Promise> { + const thisAsLeafOrContainer = this as unknown as SolidLeaf | SolidContainer; // Get the wacUri if not already present if (!options?.ignoreCache && this.wacUri) { - return { - type: "getWacUriSuccess", - wacUri: this.wacUri, - isError: false, - uri: this.uri, - }; + return new GetWacUriSuccess(thisAsLeafOrContainer, this.wacUri); } - const wacUriResult = await getWacUri(this.uri, { + const wacUriResult = await getWacUri(thisAsLeafOrContainer, { fetch: this.context.solid.fetch, }); if (wacUriResult.isError) { @@ -643,15 +641,14 @@ export abstract class SolidResource */ async getWac(options?: { ignoreCache: boolean; - }): Promise { + }): Promise< + | GetWacUriError + | GetWacRuleResult + > { + const thisAsLeafOrContainer = this as unknown as SolidLeaf | SolidContainer; // Return the wac rule if it's already cached if (!options?.ignoreCache && this.wacRule) { - return { - type: "getWacRuleSuccess", - uri: this.uri, - isError: false, - wacRule: this.wacRule, - }; + return new GetWacRuleSuccess(thisAsLeafOrContainer, this.wacRule); } // Get the wac uri @@ -659,9 +656,13 @@ export abstract class SolidResource if (wacUriResult.isError) return wacUriResult; // Get the wac rule - const wacResult = await getWacRuleWithAclUri(wacUriResult.wacUri, { - fetch: this.context.solid.fetch, - }); + const wacResult = await getWacRuleWithAclUri( + wacUriResult.wacUri, + thisAsLeafOrContainer, + { + fetch: this.context.solid.fetch, + }, + ); if (wacResult.isError) return wacResult; // If the wac rules was successfully found if (wacResult.type === "getWacRuleSuccess") { @@ -674,7 +675,7 @@ export abstract class SolidResource if (parentResource?.isError) return parentResource; if (!parentResource) { return new NoncompliantPodError( - this, + thisAsLeafOrContainer, `Resource "${this.uri}" has no Effective ACL resource`, ); } @@ -714,14 +715,20 @@ export abstract class SolidResource * }); * ``` */ - async setWac(wacRule: WacRule): Promise { + async setWac( + wacRule: WacRule, + ): Promise< + | GetWacUriError + | SetWacRuleResult + > { + const thisAsLeafOrContainer = this as unknown as SolidLeaf | SolidContainer; const wacUriResult = await this.getWacUri(); if (wacUriResult.isError) return wacUriResult; const result = await setWacRuleForAclUri( wacUriResult.wacUri, wacRule, - this.uri, + thisAsLeafOrContainer, { fetch: this.context.solid.fetch, }, diff --git a/packages/connected-solid/src/test.ts b/packages/connected-solid/src/test.ts deleted file mode 100644 index 42d5c41..0000000 --- a/packages/connected-solid/src/test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { ConnectedLdoDataset } from "@ldo/connected"; -import { solidConnectedPlugin } from "./SolidConnectedPlugin"; -import { createDatasetFactory } from "@ldo/dataset"; -import { createTransactionDatasetFactory } from "@ldo/subscribable-dataset"; - -const dataset = new ConnectedLdoDataset( - [solidConnectedPlugin], - createDatasetFactory(), - createTransactionDatasetFactory(), -); - -const stringId: string = "blah"; -const allResources = dataset.getResource(stringId); -const containerResource = dataset.getResource("https://example.com/container/"); -const leafResource = dataset.getResource( - "https://example.com/container/index.ttl", -); - -const nextGraphResource = dataset.getResource("did:ng:cool"); diff --git a/packages/connected-solid/src/util/rdfUtils.ts b/packages/connected-solid/src/util/rdfUtils.ts index d10a737..54eed0e 100644 --- a/packages/connected-solid/src/util/rdfUtils.ts +++ b/packages/connected-solid/src/util/rdfUtils.ts @@ -2,10 +2,11 @@ import type { LdoDataset } from "@ldo/ldo"; import { parseRdf } from "@ldo/ldo"; import { namedNode, quad as createQuad } from "@rdfjs/data-model"; import type { Dataset } from "@rdfjs/types"; -import type { ContainerUri } from "./uriTypes"; -import { isContainerUri } from "./uriTypes"; -import { NoncompliantPodError } from "../requester/results/error/NoncompliantPodError"; -import { UnexpectedResourceError } from "../requester/results/error/ErrorResult"; +import type { NoncompliantPodError } from "../requester/results/error/NoncompliantPodError"; +import { ErrorResult } from "@ldo/connected"; +import { UnexpectedResourceError } from "@ldo/connected"; +import type { SolidContainerUri } from "../types"; +import { isSolidContainerUri } from "./isSolidUri"; export const ldpContains = namedNode("http://www.w3.org/ns/ldp#contains"); export const rdfType = namedNode( @@ -24,7 +25,7 @@ export const ldpBasicContainer = namedNode( * @param uri - the child URI * @returns A parent URI or undefined if not possible */ -export function getParentUri(uri: string): ContainerUri | undefined { +export function getParentUri(uri: string): SolidContainerUri | undefined { const urlObject = new URL(uri); const pathItems = urlObject.pathname.split("/"); if ( @@ -38,7 +39,7 @@ export function getParentUri(uri: string): ContainerUri | undefined { } pathItems.pop(); urlObject.pathname = `${pathItems.join("/")}/`; - return urlObject.toString() as ContainerUri; + return urlObject.toString() as SolidContainerUri; } /** @@ -93,7 +94,7 @@ export function addResourceRdfToContainer( const resourceNode = namedNode(resourceUri); dataset.add(createQuad(parentNode, ldpContains, resourceNode, parentNode)); dataset.add(createQuad(resourceNode, rdfType, ldpResource, parentNode)); - if (isContainerUri(resourceUri)) { + if (isSolidContainerUri(resourceUri)) { dataset.add( createQuad(resourceNode, rdfType, ldpBasicContainer, parentNode), ); @@ -115,10 +116,10 @@ export async function addRawTurtleToDataset( rawTurtle: string, dataset: Dataset, baseUri: string, -): Promise { +): Promise { const rawTurtleResult = await rawTurtleToDataset(rawTurtle, baseUri); - if (rawTurtleResult.isError) return rawTurtleResult; - const loadedDataset = rawTurtleResult.dataset; + if (rawTurtleResult instanceof Error) return rawTurtleResult; + const loadedDataset = rawTurtleResult; const graphNode = namedNode(baseUri); // Destroy all triples that were once a part of this resouce dataset.deleteMatches(undefined, undefined, undefined, graphNode); @@ -133,17 +134,16 @@ export async function addRawTurtleToDataset( export async function rawTurtleToDataset( rawTurtle: string, baseUri: string, -): Promise<{ isError: false; dataset: LdoDataset } | NoncompliantPodError> { +): Promise { try { const loadedDataset = await parseRdf(rawTurtle, { baseIRI: baseUri, }); - return { isError: false, dataset: loadedDataset }; + return loadedDataset; } catch (err) { - const error = UnexpectedResourceError.fromThrown(baseUri, err); - return new NoncompliantPodError( - baseUri, - `Request returned noncompliant turtle: ${error.message}\n${rawTurtle}`, + const message = err instanceof Error ? err.message : ""; + return new Error( + `Request returned noncompliant turtle: ${message}\n${rawTurtle}`, ); } } diff --git a/packages/connected-solid/src/wac/getWacRule.ts b/packages/connected-solid/src/wac/getWacRule.ts index 3c2b68f..8f6568e 100644 --- a/packages/connected-solid/src/wac/getWacRule.ts +++ b/packages/connected-solid/src/wac/getWacRule.ts @@ -1,24 +1,29 @@ -import type { GetWacRuleSuccess } from "./results/GetWacRuleSuccess"; -import { guaranteeFetch } from "../../util/guaranteeFetch"; -import type { BasicRequestOptions } from "../../requester/requests/requestOptions"; -import type { HttpErrorResultType } from "../../requester/results/error/HttpErrorResult"; -import { HttpErrorResult } from "../../requester/results/error/HttpErrorResult"; -import type { NoncompliantPodError } from "../../requester/results/error/NoncompliantPodError"; -import type { UnexpectedResourceError } from "../../requester/results/error/ErrorResult"; -import { rawTurtleToDataset } from "../../util/rdfUtils"; -import { AuthorizationShapeType } from "../../.ldo/wac.shapeTypes"; +import { GetWacRuleSuccess } from "./results/GetWacRuleSuccess"; +import { AuthorizationShapeType } from "../.ldo/wac.shapeTypes"; import type { AccessModeList, WacRule } from "./WacRule"; -import type { Authorization } from "../../.ldo/wac.typings"; -import type { WacRuleAbsent } from "./results/WacRuleAbsent"; +import type { Authorization } from "../.ldo/wac.typings"; +import { WacRuleAbsent } from "./results/WacRuleAbsent"; +import { + HttpErrorResult, + type HttpErrorResultType, +} from "../requester/results/error/HttpErrorResult"; +import { NoncompliantPodError } from "../requester/results/error/NoncompliantPodError"; +import type { UnexpectedResourceError } from "@ldo/connected"; +import type { SolidLeaf } from "../resources/SolidLeaf"; +import type { SolidContainer } from "../resources/SolidContainer"; +import { guaranteeFetch } from "../util/guaranteeFetch"; +import type { BasicRequestOptions } from "../requester/requests/requestOptions"; +import { rawTurtleToDataset } from "../util/rdfUtils"; -export type GetWacRuleError = - | HttpErrorResultType - | NoncompliantPodError - | UnexpectedResourceError; -export type GetWacRuleResult = - | GetWacRuleSuccess - | GetWacRuleError - | WacRuleAbsent; +export type GetWacRuleError = + | HttpErrorResultType + | NoncompliantPodError + | UnexpectedResourceError; + +export type GetWacRuleResult = + | GetWacRuleSuccess + | GetWacRuleError + | WacRuleAbsent; /** * Given the URI of an ACL document, return the Web Access Control (WAC) rules @@ -28,26 +33,39 @@ export type GetWacRuleResult = */ export async function getWacRuleWithAclUri( aclUri: string, + resource: SolidContainer, + options?: BasicRequestOptions, +): Promise>; +export async function getWacRuleWithAclUri( + aclUri: string, + resource: SolidLeaf, options?: BasicRequestOptions, -): Promise { +): Promise>; +export async function getWacRuleWithAclUri( + aclUri: string, + resource: SolidLeaf | SolidContainer, + options?: BasicRequestOptions, +): Promise>; +export async function getWacRuleWithAclUri( + aclUri: string, + resource: SolidLeaf | SolidContainer, + options?: BasicRequestOptions, +): Promise> { const fetch = guaranteeFetch(options?.fetch); const response = await fetch(aclUri); - const errorResult = HttpErrorResult.checkResponse(aclUri, response); + const errorResult = HttpErrorResult.checkResponse(resource, response); if (errorResult) return errorResult; if (response.status === 404) { - return { - type: "wacRuleAbsent", - uri: aclUri, - isError: false, - }; + return new WacRuleAbsent(resource); } // Parse Turtle const rawTurtle = await response.text(); const rawTurtleResult = await rawTurtleToDataset(rawTurtle, aclUri); - if (rawTurtleResult.isError) return rawTurtleResult; - const dataset = rawTurtleResult.dataset; + if (rawTurtleResult instanceof Error) + return new NoncompliantPodError(resource, rawTurtleResult.message); + const dataset = rawTurtleResult; const authorizations = dataset .usingType(AuthorizationShapeType) .matchSubject( @@ -109,10 +127,5 @@ export async function getWacRuleWithAclUri( }); }); - return { - type: "getWacRuleSuccess", - uri: aclUri, - isError: false, - wacRule, - }; + return new GetWacRuleSuccess(resource, wacRule); } diff --git a/packages/connected-solid/src/wac/getWacUri.ts b/packages/connected-solid/src/wac/getWacUri.ts index d402c8b..0c3178d 100644 --- a/packages/connected-solid/src/wac/getWacUri.ts +++ b/packages/connected-solid/src/wac/getWacUri.ts @@ -1,22 +1,26 @@ -import type { GetWacUriSuccess } from "./results/GetWacUriSuccess"; -import type { HttpErrorResultType } from "../../requester/results/error/HttpErrorResult"; import { HttpErrorResult, NotFoundHttpError, -} from "../../requester/results/error/HttpErrorResult"; -import { UnexpectedResourceError } from "../../requester/results/error/ErrorResult"; -import { guaranteeFetch } from "../../util/guaranteeFetch"; -import type { BasicRequestOptions } from "../../requester/requests/requestOptions"; -import { NoncompliantPodError } from "../../requester/results/error/NoncompliantPodError"; +} from "../requester/results/error/HttpErrorResult"; +import type { HttpErrorResultType } from "../requester/results/error/HttpErrorResult"; +import { GetWacUriSuccess } from "./results/GetWacUriSuccess"; import { parse as parseLinkHeader } from "http-link-header"; -import type { LeafUri } from "../../util/uriTypes"; +import { UnexpectedResourceError } from "@ldo/connected"; +import { NoncompliantPodError } from "../requester/results/error/NoncompliantPodError"; +import type { SolidContainer } from "../resources/SolidContainer"; +import type { SolidLeaf } from "../resources/SolidLeaf"; +import type { BasicRequestOptions } from "../requester/requests/requestOptions"; +import { guaranteeFetch } from "../util/guaranteeFetch"; +import type { SolidLeafUri } from "../types"; -export type GetWacUriError = - | HttpErrorResultType - | NotFoundHttpError - | NoncompliantPodError - | UnexpectedResourceError; -export type GetWacUriResult = GetWacUriSuccess | GetWacUriError; +export type GetWacUriError = + | HttpErrorResultType + | NotFoundHttpError + | NoncompliantPodError + | UnexpectedResourceError; +export type GetWacUriResult = + | GetWacUriSuccess + | GetWacUriError; /** * Get the URI for the WAC rules of a specific resource @@ -25,19 +29,19 @@ export type GetWacUriResult = GetWacUriSuccess | GetWacUriError; * @returns GetWacUriResult */ export async function getWacUri( - resourceUri: string, + resource: SolidLeaf | SolidContainer, options?: BasicRequestOptions, -): Promise { +): Promise> { try { const fetch = guaranteeFetch(options?.fetch); - const response = await fetch(resourceUri, { + const response = await fetch(resource.uri, { method: "head", }); - const errorResult = HttpErrorResult.checkResponse(resourceUri, response); + const errorResult = HttpErrorResult.checkResponse(resource, response); if (errorResult) return errorResult; if (NotFoundHttpError.is(response)) { return new NotFoundHttpError( - resourceUri, + resource, response, "Could not get access control rules because the resource does not exist.", ); @@ -46,7 +50,7 @@ export async function getWacUri( const linkHeader = response.headers.get("link"); if (!linkHeader) { return new NoncompliantPodError( - resourceUri, + resource, "No link header present in request.", ); } @@ -54,17 +58,13 @@ export async function getWacUri( const aclUris = parsedLinkHeader.get("rel", "acl"); if (aclUris.length !== 1) { return new NoncompliantPodError( - resourceUri, + resource, `There must be one link with a rel="acl"`, ); } - return { - type: "getWacUriSuccess", - isError: false, - uri: resourceUri, - wacUri: aclUris[0].uri as LeafUri, - }; + + return new GetWacUriSuccess(resource, aclUris[0].uri as SolidLeafUri); } catch (err: unknown) { - return UnexpectedResourceError.fromThrown(resourceUri, err); + return UnexpectedResourceError.fromThrown(resource, err); } } diff --git a/packages/connected-solid/src/wac/results/GetWacRuleSuccess.ts b/packages/connected-solid/src/wac/results/GetWacRuleSuccess.ts index 4dd17b6..5dcb8e1 100644 --- a/packages/connected-solid/src/wac/results/GetWacRuleSuccess.ts +++ b/packages/connected-solid/src/wac/results/GetWacRuleSuccess.ts @@ -1,13 +1,22 @@ -import type { ResourceSuccess } from "../../../requester/results/success/SuccessResult"; +import { ResourceSuccess } from "@ldo/connected"; import type { WacRule } from "../WacRule"; +import type { SolidLeaf } from "../../resources/SolidLeaf"; +import type { SolidContainer } from "../../resources/SolidContainer"; /** * Returned when a WAC rule is successfully retrieved */ -export interface GetWacRuleSuccess extends ResourceSuccess { - type: "getWacRuleSuccess"; +export class GetWacRuleSuccess< + ResourceType extends SolidLeaf | SolidContainer, +> extends ResourceSuccess { + type = "getWacRuleSuccess" as const; /** * The rule that was retrieved */ wacRule: WacRule; + + constructor(resoure: ResourceType, wacRule: WacRule) { + super(resoure); + this.wacRule = wacRule; + } } diff --git a/packages/connected-solid/src/wac/results/GetWacUriSuccess.ts b/packages/connected-solid/src/wac/results/GetWacUriSuccess.ts index 3694d9f..7327165 100644 --- a/packages/connected-solid/src/wac/results/GetWacUriSuccess.ts +++ b/packages/connected-solid/src/wac/results/GetWacUriSuccess.ts @@ -1,13 +1,22 @@ -import type { ResourceSuccess } from "../../../requester/results/success/SuccessResult"; -import type { LeafUri } from "../../../util/uriTypes"; +import { ResourceSuccess } from "@ldo/connected"; +import type { SolidLeafUri } from "../../types"; +import type { SolidContainer } from "../../resources/SolidContainer"; +import type { SolidLeaf } from "../../resources/SolidLeaf"; /** * Returned when the URI for a resources ACL document was successfully retried */ -export interface GetWacUriSuccess extends ResourceSuccess { - type: "getWacUriSuccess"; +export class GetWacUriSuccess< + ResourceType extends SolidContainer | SolidLeaf, +> extends ResourceSuccess { + type = "getWacUriSuccess" as const; /** * The URI of the ACL document */ - wacUri: LeafUri; + wacUri: SolidLeafUri; + + constructor(resource: ResourceType, wacUri: SolidLeafUri) { + super(resource); + this.wacUri = wacUri; + } } diff --git a/packages/connected-solid/src/wac/results/SetWacRuleSuccess.ts b/packages/connected-solid/src/wac/results/SetWacRuleSuccess.ts index a79b928..b94e4de 100644 --- a/packages/connected-solid/src/wac/results/SetWacRuleSuccess.ts +++ b/packages/connected-solid/src/wac/results/SetWacRuleSuccess.ts @@ -1,13 +1,22 @@ -import type { ResourceSuccess } from "../../../requester/results/success/SuccessResult"; +import { ResourceSuccess } from "@ldo/connected"; import type { WacRule } from "../WacRule"; +import type { SolidContainer } from "../../resources/SolidContainer"; +import type { SolidLeaf } from "../../resources/SolidLeaf"; /** * Returned when rules were successfully written */ -export interface SetWacRuleSuccess extends ResourceSuccess { - type: "setWacRuleSuccess"; +export class SetWacRuleSuccess< + ResourceType extends SolidLeaf | SolidContainer, +> extends ResourceSuccess { + type = "setWacRuleSuccess" as const; /** * The written rule */ wacRule: WacRule; + + constructor(resource: ResourceType, wacRule: WacRule) { + super(resource); + this.wacRule = wacRule; + } } diff --git a/packages/connected-solid/src/wac/results/WacRuleAbsent.ts b/packages/connected-solid/src/wac/results/WacRuleAbsent.ts index 7bec46a..d5e12b7 100644 --- a/packages/connected-solid/src/wac/results/WacRuleAbsent.ts +++ b/packages/connected-solid/src/wac/results/WacRuleAbsent.ts @@ -1,8 +1,12 @@ -import type { ResourceSuccess } from "../../../requester/results/success/SuccessResult"; +import { ResourceSuccess } from "@ldo/connected"; +import type { SolidLeaf } from "../../resources/SolidLeaf"; +import type { SolidContainer } from "../../resources/SolidContainer"; /** * Returned if no WAC rule was returned from the server */ -export interface WacRuleAbsent extends ResourceSuccess { - type: "wacRuleAbsent"; +export class WacRuleAbsent< + ResourceType extends SolidLeaf | SolidContainer, +> extends ResourceSuccess { + type = "wacRuleAbsent" as const; } diff --git a/packages/connected-solid/src/wac/setWacRule.ts b/packages/connected-solid/src/wac/setWacRule.ts index 1569cb7..9be8254 100644 --- a/packages/connected-solid/src/wac/setWacRule.ts +++ b/packages/connected-solid/src/wac/setWacRule.ts @@ -1,20 +1,27 @@ import { createLdoDataset } from "@ldo/ldo"; -import type { BasicRequestOptions } from "../../requester/requests/requestOptions"; -import type { UnexpectedResourceError } from "../../requester/results/error/ErrorResult"; +import type { AccessModeList, WacRule } from "./WacRule"; +import { SetWacRuleSuccess } from "./results/SetWacRuleSuccess"; +import type { Authorization } from "../.ldo/wac.typings"; +import { AuthorizationShapeType } from "../.ldo/wac.shapeTypes"; +import { v4 } from "uuid"; +import { guaranteeFetch } from "../util/guaranteeFetch"; +import type { SolidLeafUri } from "../types"; +import type { SolidLeaf } from "../resources/SolidLeaf"; +import type { SolidContainer } from "../resources/SolidContainer"; import { HttpErrorResult, type HttpErrorResultType, -} from "../../requester/results/error/HttpErrorResult"; -import { isContainerUri, type LeafUri } from "../../util/uriTypes"; -import type { AccessModeList, WacRule } from "./WacRule"; -import type { SetWacRuleSuccess } from "./results/SetWacRuleSuccess"; -import type { Authorization } from "../../.ldo/wac.typings"; -import { AuthorizationShapeType } from "../../.ldo/wac.shapeTypes"; -import { v4 } from "uuid"; -import { guaranteeFetch } from "../../util/guaranteeFetch"; +} from "../requester/results/error/HttpErrorResult"; +import type { UnexpectedResourceError } from "@ldo/connected"; +import type { BasicRequestOptions } from "../requester/requests/requestOptions"; +import { isContainerUri } from "@ldo/solid"; -export type SetWacRuleError = HttpErrorResultType | UnexpectedResourceError; -export type SetWacRuleResult = SetWacRuleSuccess | SetWacRuleError; +export type SetWacRuleError = + | HttpErrorResultType + | UnexpectedResourceError; +export type SetWacRuleResult = + | SetWacRuleSuccess + | SetWacRuleError; /** * Given the URI of an ACL document and some WAC rules, set the WAC rules of @@ -26,11 +33,29 @@ export type SetWacRuleResult = SetWacRuleSuccess | SetWacRuleError; * @returns SetWacRuleResult */ export async function setWacRuleForAclUri( - aclUri: LeafUri, + aclUri: SolidLeafUri, + newRule: WacRule, + resource: SolidContainer, + options?: BasicRequestOptions, +): Promise>; +export async function setWacRuleForAclUri( + aclUri: SolidLeafUri, + newRule: WacRule, + resource: SolidLeaf, + options?: BasicRequestOptions, +): Promise>; +export async function setWacRuleForAclUri( + aclUri: SolidLeafUri, + newRule: WacRule, + resource: SolidContainer | SolidLeaf, + options?: BasicRequestOptions, +): Promise>; +export async function setWacRuleForAclUri( + aclUri: SolidLeafUri, newRule: WacRule, - accessTo: string, + resource: SolidContainer | SolidLeaf, options?: BasicRequestOptions, -): Promise { +): Promise> { const fetch = guaranteeFetch(options?.fetch); // The rule map keeps track of all the rules that are currently being used // so that similar rules can be grouped together @@ -56,9 +81,9 @@ export async function setWacRuleForAclUri( if (accessModeList.write) authorization.mode?.add({ "@id": "Write" }); if (accessModeList.append) authorization.mode?.add({ "@id": "Append" }); if (accessModeList.control) authorization.mode?.add({ "@id": "Control" }); - authorization.accessTo = { "@id": accessTo }; - if (isContainerUri(accessTo)) { - authorization.default = { "@id": accessTo }; + authorization.accessTo = { "@id": resource.uri }; + if (isContainerUri(resource.uri)) { + authorization.default = { "@id": resource.uri }; } ruleMap[accessModeListHash] = authorization; } @@ -88,15 +113,10 @@ export async function setWacRuleForAclUri( }, body: dataset.toString(), }); - const errorResult = HttpErrorResult.checkResponse(aclUri, response); + const errorResult = HttpErrorResult.checkResponse(resource, response); if (errorResult) return errorResult; - return { - type: "setWacRuleSuccess", - uri: aclUri, - isError: false, - wacRule: newRule, - }; + return new SetWacRuleSuccess(resource, newRule); } // Hashes the access mode list for use in the rule map