Setup tests for Link Traversal

main
Jackson Morgan 4 months ago
parent a78a604a18
commit fabd0c0c58
  1. 4
      package-lock.json
  2. 7
      packages/connected-solid/src/SolidConnectedPlugin.ts
  3. 6
      packages/connected/package.json
  4. 14
      packages/connected/src/ConnectedLdoDataset.ts
  5. 8
      packages/connected/src/ConnectedLdoTransactionDataset.ts
  6. 27
      packages/connected/src/types/IConnectedLdoDataset.ts
  7. 49
      packages/connected/src/types/ILinkQuery.ts
  8. 459
      packages/connected/test/.ldo/solidProfile.context.ts
  9. 749
      packages/connected/test/.ldo/solidProfile.schema.ts
  10. 71
      packages/connected/test/.ldo/solidProfile.shapeTypes.ts
  11. 293
      packages/connected/test/.ldo/solidProfile.typings.ts
  12. 121
      packages/connected/test/.shapes/solidProfile.shex
  13. 42
      packages/connected/test/LinkTraversalData.ts
  14. 132
      packages/connected/test/LinkTraversalIntegration.test.ts
  15. 112
      packages/connected/test/authFetch.helper.ts
  16. 44
      packages/connected/test/configs/server-config-without-websocket.json
  17. 43
      packages/connected/test/configs/server-config.json
  18. 9
      packages/connected/test/configs/solid-css-seed.json
  19. 3
      packages/connected/test/setup-tests.ts
  20. 42
      packages/connected/test/solidServer.helper.ts
  21. 14
      packages/test-solid-server/Readme.md
  22. 2
      packages/test-solid-server/src/authFetch.ts

4
package-lock.json generated

@ -25931,6 +25931,7 @@
}, },
"devDependencies": { "devDependencies": {
"@ldo/connected-solid": "^1.0.0-alpha.3", "@ldo/connected-solid": "^1.0.0-alpha.3",
"@ldo/test-solid-server": "^1.0.0-alpha.8",
"@rdfjs/data-model": "^1.2.0", "@rdfjs/data-model": "^1.2.0",
"@rdfjs/types": "^1.0.1", "@rdfjs/types": "^1.0.1",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
@ -25989,6 +25990,7 @@
"devDependencies": { "devDependencies": {
"@inrupt/solid-client-authn-core": "^2.2.6", "@inrupt/solid-client-authn-core": "^2.2.6",
"@ldo/cli": "^1.0.0-alpha.3", "@ldo/cli": "^1.0.0-alpha.3",
"@ldo/test-solid-server": "^1.0.0-alpha.8",
"@rdfjs/data-model": "^1.2.0", "@rdfjs/data-model": "^1.2.0",
"@rdfjs/types": "^1.0.1", "@rdfjs/types": "^1.0.1",
"@solid-notifications/types": "^0.1.2", "@solid-notifications/types": "^0.1.2",
@ -26332,7 +26334,7 @@
}, },
"packages/test-solid-server": { "packages/test-solid-server": {
"name": "@ldo/test-solid-server", "name": "@ldo/test-solid-server",
"version": "1.0.0-alpha.3", "version": "1.0.0-alpha.8",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@inrupt/solid-client-authn-core": "^2.2.6", "@inrupt/solid-client-authn-core": "^2.2.6",

@ -80,4 +80,11 @@ export const solidConnectedPlugin: SolidConnectedPlugin = {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore "Types" only exists for the typing system // @ts-ignore "Types" only exists for the typing system
types: {}, types: {},
normalizeUri(uri: SolidUri): SolidUri {
const url = new URL(uri);
url.hash = "";
url.search = "";
return url.toString() as SolidUri;
},
}; };

@ -6,11 +6,12 @@
"scripts": { "scripts": {
"build": "tsc --project tsconfig.build.json", "build": "tsc --project tsconfig.build.json",
"watch": "tsc --watch", "watch": "tsc --watch",
"test": "jest --coverage", "test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --coverage",
"test:watch": "jest --watch", "test:watch": "jest --watch",
"prepublishOnly": "npm run test && npm run build", "prepublishOnly": "npm run test && npm run build",
"lint": "eslint src/** --fix --no-error-on-unmatched-pattern", "lint": "eslint src/** --fix --no-error-on-unmatched-pattern",
"docs": "typedoc --plugin typedoc-plugin-markdown" "docs": "typedoc --plugin typedoc-plugin-markdown",
"build:ldo": "ldo build --input test/.shapes --output test/.ldo"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -24,6 +25,7 @@
"homepage": "https://github.com/o-development/ldobjects/tree/main/packages/solid#readme", "homepage": "https://github.com/o-development/ldobjects/tree/main/packages/solid#readme",
"devDependencies": { "devDependencies": {
"@ldo/connected-solid": "^1.0.0-alpha.3", "@ldo/connected-solid": "^1.0.0-alpha.3",
"@ldo/test-solid-server": "^1.0.0-alpha.8",
"@rdfjs/data-model": "^1.2.0", "@rdfjs/data-model": "^1.2.0",
"@rdfjs/types": "^1.0.1", "@rdfjs/types": "^1.0.1",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",

@ -153,6 +153,10 @@ export class ConnectedLdoDataset<
if (!plugin) return new InvalidIdentifierResource(uri) as any; if (!plugin) return new InvalidIdentifierResource(uri) as any;
const normalizedUri = plugin.normalizeUri?.(uri) ?? uri; const normalizedUri = plugin.normalizeUri?.(uri) ?? uri;
console.log("plugin", plugin);
console.log("func", plugin.normalizeUri);
console.log(normalizedUri);
let resource = this.resourceMap.get(normalizedUri); let resource = this.resourceMap.get(normalizedUri);
if (!resource) { if (!resource) {
resource = plugin.getResource(uri, this.context); resource = plugin.getResource(uri, this.context);
@ -162,6 +166,16 @@ export class ConnectedLdoDataset<
return resource as any; return resource as any;
} }
getResources(): GetResourceReturnType<Plugins[number], string>[] {
console.log("IM IN HERE");
console.log(this.resourceMap);
return Array.from(this.resourceMap.values());
}
getFetchedResources(): GetResourceReturnType<Plugins[number], string>[] {
return this.getResources().filter((resource) => resource.isFetched());
}
/** /**
* Generates a random uri and creates a resource. * Generates a random uri and creates a resource.
* *

@ -101,6 +101,14 @@ export class ConnectedLdoTransactionDataset<Plugins extends ConnectedPlugin[]>
return this.context.dataset.getResource(uri, pluginName); return this.context.dataset.getResource(uri, pluginName);
} }
getResources(): Plugins[number]["types"]["resource"][] {
return this.context.dataset.getResources();
}
getFetchedResources(): Plugins[number]["types"]["resource"][] {
return this.context.dataset.getFetchedResources();
}
createResource< createResource<
Name extends Plugins[number]["name"], Name extends Plugins[number]["name"],
Plugin extends Extract<Plugins[number], { name: Name }>, Plugin extends Extract<Plugins[number], { name: Name }>,

@ -79,6 +79,33 @@ export interface IConnectedLdoDataset<Plugins extends ConnectedPlugin[]>
pluginName?: Name, pluginName?: Name,
): GetResourceReturnType<Plugin, UriType>; ): GetResourceReturnType<Plugin, UriType>;
/**
* Retireves a representation of all Resources referenced by this dataset
* This does not necessarily mean that it's been fetched (use the
* `getFetchedResources` method for that). It simply means that at one point
* it was referenced.
*
* @returns a Resource array
*
* @example
* ```typescript
* const allResources = connectedLdoDataset.getResources();
* ```
*/
getResources(): Plugins[number]["types"]["resource"][];
/**
* Retireves a representation of all Resources that have been fetched.
*
* @returns a Resource array
*
* @example
* ```typescript
* const allResources = connectedLdoDataset.getFetchedResources();
* ```
*/
getFetchedResources(): Plugins[number]["types"]["resource"][];
/** /**
* Generates a random uri and creates a resource. * Generates a random uri and creates a resource.
* *

@ -3,8 +3,9 @@
// If I ever want to implement a global query interface, this is a good place // If I ever want to implement a global query interface, this is a good place
// to start. // to start.
import type { LdoBase, LdSet, ShapeType } from "@ldo/ldo"; import type { LdoBase, LdSet } from "@ldo/ldo";
import { ProfileShapeType } from "packages/ldo/test/profileData"; // import { SolidProfileShapeShapeType } from "../../test/.ldo/solidProfile.shapeTypes";
// import type { SolidProfileShape } from "../../test/.ldo/solidProfile.typings";
/** /**
* Link Query Input * Link Query Input
@ -12,7 +13,7 @@ import { ProfileShapeType } from "packages/ldo/test/profileData";
export type LQInput<Type> = LQInputObject<Type>; export type LQInput<Type> = LQInputObject<Type>;
export type LQInputObject<Type> = Partial<{ export type LQInputObject<Type> = Partial<{
[key in keyof Type]: LQInputFlattenSet<Type[key]>; [key in Exclude<keyof Type, "@context">]: LQInputFlattenSet<Type[key]>;
}>; }>;
export type LQInputSubSet<Type> = Type extends object export type LQInputSubSet<Type> = Type extends object
@ -45,7 +46,10 @@ export type LQReturn<Type, Input extends LQInput<Type>> = LQReturnObject<
>; >;
export type LQReturnObject<Type, Input extends LQInputObject<Type>> = { export type LQReturnObject<Type, Input extends LQInputObject<Type>> = {
[key in keyof Required<Type> as undefined extends Input[key] [key in Exclude<
keyof Required<Type>,
"@context"
> as undefined extends Input[key]
? never ? never
: key]: Input[key] extends LQInputFlattenSet<Type[key]> : key]: Input[key] extends LQInputFlattenSet<Type[key]>
? undefined extends Type[key] ? undefined extends Type[key]
@ -56,7 +60,9 @@ export type LQReturnObject<Type, Input extends LQInputObject<Type>> = {
export type LQReturnSubSet<Type, Input> = Input extends LQInputSubSet<Type> export type LQReturnSubSet<Type, Input> = Input extends LQInputSubSet<Type>
? Input extends LQInputObject<Type> ? Input extends LQInputObject<Type>
? LQReturnObject<Type, Input> ? Input extends true
? Type
: LQReturnObject<Type, Input>
: Type : Type
: never; : never;
@ -89,20 +95,31 @@ export interface ILinkQuery<Type extends LdoBase, Input extends LQInput<Type>> {
fromSubject(): ExpandDeep<LQReturn<Type, Input>>; fromSubject(): ExpandDeep<LQReturn<Type, Input>>;
} }
// TODO: Remove test functions
// function test<Type extends LdoBase, Input extends LQInput<Type>>( // function test<Type extends LdoBase, Input extends LQInput<Type>>(
// _shapeType: ShapeType<Type>, // shapeType: ShapeType<Type>,
// _input: Input, // input: Input,
// ): ExpandDeep<LQReturn<Type, Input>> { // ): ExpandDeep<LQReturn<Type, Input>> {
// throw new Error("Not Implemeneted"); // throw new Error("Not Implemented");
// } // }
// const result = test(ProfileShapeType, {
// fn: true, // type TestLQInput = {
// name: true;
// knows: {
// name: true;
// };
// };
// type testReturn = LQReturn<SolidProfileShape, TestLQInput>;
// type test2 = LQReturnSubSet<string | undefined, true>;
// type lqInputObject = LQInputObject<string | undefined>;
// type meh = TestLQInput extends true ? true : false;
// const thing = test(SolidProfileShapeShapeType, {
// name: true,
// knows: {
// name: true, // name: true,
// hasTelephone: {
// type: {
// "@id": true,
// },
// value: true,
// }, // },
// }); // });

@ -0,0 +1,459 @@
import { LdoJsonldContext } from "@ldo/ldo";
/**
* =============================================================================
* solidProfileContext: JSONLD Context for solidProfile
* =============================================================================
*/
export const solidProfileContext: LdoJsonldContext = {
type: {
"@id": "@type",
},
Person: {
"@id": "http://schema.org/Person",
"@context": {
type: {
"@id": "@type",
},
fn: {
"@id": "http://www.w3.org/2006/vcard/ns#fn",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
name: {
"@id": "http://xmlns.com/foaf/0.1/name",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
hasAddress: {
"@id": "http://www.w3.org/2006/vcard/ns#hasAddress",
"@type": "@id",
"@isCollection": true,
},
hasEmail: {
"@id": "http://www.w3.org/2006/vcard/ns#hasEmail",
"@type": "@id",
"@isCollection": true,
},
hasPhoto: {
"@id": "http://www.w3.org/2006/vcard/ns#hasPhoto",
"@type": "@id",
},
img: {
"@id": "http://xmlns.com/foaf/0.1/img",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
hasTelephone: {
"@id": "http://www.w3.org/2006/vcard/ns#hasTelephone",
"@type": "@id",
"@isCollection": true,
},
phone: {
"@id": "http://www.w3.org/2006/vcard/ns#phone",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
organizationName: {
"@id": "http://www.w3.org/2006/vcard/ns#organization-name",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
role: {
"@id": "http://www.w3.org/2006/vcard/ns#role",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
trustedApp: {
"@id": "http://www.w3.org/ns/auth/acl#trustedApp",
"@type": "@id",
"@isCollection": true,
},
key: {
"@id": "http://www.w3.org/ns/auth/cert#key",
"@type": "@id",
"@isCollection": true,
},
inbox: {
"@id": "http://www.w3.org/ns/ldp#inbox",
"@type": "@id",
},
preferencesFile: {
"@id": "http://www.w3.org/ns/pim/space#preferencesFile",
"@type": "@id",
},
storage: {
"@id": "http://www.w3.org/ns/pim/space#storage",
"@type": "@id",
"@isCollection": true,
},
account: {
"@id": "http://www.w3.org/ns/solid/terms#account",
"@type": "@id",
},
privateTypeIndex: {
"@id": "http://www.w3.org/ns/solid/terms#privateTypeIndex",
"@type": "@id",
"@isCollection": true,
},
publicTypeIndex: {
"@id": "http://www.w3.org/ns/solid/terms#publicTypeIndex",
"@type": "@id",
"@isCollection": true,
},
knows: {
"@id": "http://xmlns.com/foaf/0.1/knows",
"@type": "@id",
"@isCollection": true,
},
},
},
Person2: {
"@id": "http://xmlns.com/foaf/0.1/Person",
"@context": {
type: {
"@id": "@type",
},
fn: {
"@id": "http://www.w3.org/2006/vcard/ns#fn",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
name: {
"@id": "http://xmlns.com/foaf/0.1/name",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
hasAddress: {
"@id": "http://www.w3.org/2006/vcard/ns#hasAddress",
"@type": "@id",
"@isCollection": true,
},
hasEmail: {
"@id": "http://www.w3.org/2006/vcard/ns#hasEmail",
"@type": "@id",
"@isCollection": true,
},
hasPhoto: {
"@id": "http://www.w3.org/2006/vcard/ns#hasPhoto",
"@type": "@id",
},
img: {
"@id": "http://xmlns.com/foaf/0.1/img",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
hasTelephone: {
"@id": "http://www.w3.org/2006/vcard/ns#hasTelephone",
"@type": "@id",
"@isCollection": true,
},
phone: {
"@id": "http://www.w3.org/2006/vcard/ns#phone",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
organizationName: {
"@id": "http://www.w3.org/2006/vcard/ns#organization-name",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
role: {
"@id": "http://www.w3.org/2006/vcard/ns#role",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
trustedApp: {
"@id": "http://www.w3.org/ns/auth/acl#trustedApp",
"@type": "@id",
"@isCollection": true,
},
key: {
"@id": "http://www.w3.org/ns/auth/cert#key",
"@type": "@id",
"@isCollection": true,
},
inbox: {
"@id": "http://www.w3.org/ns/ldp#inbox",
"@type": "@id",
},
preferencesFile: {
"@id": "http://www.w3.org/ns/pim/space#preferencesFile",
"@type": "@id",
},
storage: {
"@id": "http://www.w3.org/ns/pim/space#storage",
"@type": "@id",
"@isCollection": true,
},
account: {
"@id": "http://www.w3.org/ns/solid/terms#account",
"@type": "@id",
},
privateTypeIndex: {
"@id": "http://www.w3.org/ns/solid/terms#privateTypeIndex",
"@type": "@id",
"@isCollection": true,
},
publicTypeIndex: {
"@id": "http://www.w3.org/ns/solid/terms#publicTypeIndex",
"@type": "@id",
"@isCollection": true,
},
knows: {
"@id": "http://xmlns.com/foaf/0.1/knows",
"@type": "@id",
"@isCollection": true,
},
},
},
fn: {
"@id": "http://www.w3.org/2006/vcard/ns#fn",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
name: {
"@id": "http://xmlns.com/foaf/0.1/name",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
hasAddress: {
"@id": "http://www.w3.org/2006/vcard/ns#hasAddress",
"@type": "@id",
"@isCollection": true,
},
countryName: {
"@id": "http://www.w3.org/2006/vcard/ns#country-name",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
locality: {
"@id": "http://www.w3.org/2006/vcard/ns#locality",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
postalCode: {
"@id": "http://www.w3.org/2006/vcard/ns#postal-code",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
region: {
"@id": "http://www.w3.org/2006/vcard/ns#region",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
streetAddress: {
"@id": "http://www.w3.org/2006/vcard/ns#street-address",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
hasEmail: {
"@id": "http://www.w3.org/2006/vcard/ns#hasEmail",
"@type": "@id",
"@isCollection": true,
},
Dom: {
"@id": "http://www.w3.org/2006/vcard/ns#Dom",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
Home: {
"@id": "http://www.w3.org/2006/vcard/ns#Home",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
ISDN: {
"@id": "http://www.w3.org/2006/vcard/ns#ISDN",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
Internet: {
"@id": "http://www.w3.org/2006/vcard/ns#Internet",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
Intl: {
"@id": "http://www.w3.org/2006/vcard/ns#Intl",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
Label: {
"@id": "http://www.w3.org/2006/vcard/ns#Label",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
Parcel: {
"@id": "http://www.w3.org/2006/vcard/ns#Parcel",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
Postal: {
"@id": "http://www.w3.org/2006/vcard/ns#Postal",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
Pref: {
"@id": "http://www.w3.org/2006/vcard/ns#Pref",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
Work: {
"@id": "http://www.w3.org/2006/vcard/ns#Work",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
X400: {
"@id": "http://www.w3.org/2006/vcard/ns#X400",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
hasPhoto: {
"@id": "http://www.w3.org/2006/vcard/ns#hasPhoto",
"@type": "@id",
},
img: {
"@id": "http://xmlns.com/foaf/0.1/img",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
hasTelephone: {
"@id": "http://www.w3.org/2006/vcard/ns#hasTelephone",
"@type": "@id",
"@isCollection": true,
},
phone: {
"@id": "http://www.w3.org/2006/vcard/ns#phone",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
organizationName: {
"@id": "http://www.w3.org/2006/vcard/ns#organization-name",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
role: {
"@id": "http://www.w3.org/2006/vcard/ns#role",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
trustedApp: {
"@id": "http://www.w3.org/ns/auth/acl#trustedApp",
"@type": "@id",
"@isCollection": true,
},
mode: {
"@id": "http://www.w3.org/ns/auth/acl#mode",
"@isCollection": true,
},
Append: "http://www.w3.org/ns/auth/acl#Append",
Control: "http://www.w3.org/ns/auth/acl#Control",
Read: "http://www.w3.org/ns/auth/acl#Read",
Write: "http://www.w3.org/ns/auth/acl#Write",
origin: {
"@id": "http://www.w3.org/ns/auth/acl#origin",
"@type": "@id",
},
key: {
"@id": "http://www.w3.org/ns/auth/cert#key",
"@type": "@id",
"@isCollection": true,
},
modulus: {
"@id": "http://www.w3.org/ns/auth/cert#modulus",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
exponent: {
"@id": "http://www.w3.org/ns/auth/cert#exponent",
"@type": "http://www.w3.org/2001/XMLSchema#integer",
},
inbox: {
"@id": "http://www.w3.org/ns/ldp#inbox",
"@type": "@id",
},
preferencesFile: {
"@id": "http://www.w3.org/ns/pim/space#preferencesFile",
"@type": "@id",
},
storage: {
"@id": "http://www.w3.org/ns/pim/space#storage",
"@type": "@id",
"@isCollection": true,
},
account: {
"@id": "http://www.w3.org/ns/solid/terms#account",
"@type": "@id",
},
privateTypeIndex: {
"@id": "http://www.w3.org/ns/solid/terms#privateTypeIndex",
"@type": "@id",
"@isCollection": true,
},
publicTypeIndex: {
"@id": "http://www.w3.org/ns/solid/terms#publicTypeIndex",
"@type": "@id",
"@isCollection": true,
},
knows: {
"@id": "http://xmlns.com/foaf/0.1/knows",
"@type": "@id",
"@isCollection": true,
},
};

@ -0,0 +1,749 @@
import { Schema } from "shexj";
/**
* =============================================================================
* solidProfileSchema: ShexJ Schema for solidProfile
* =============================================================================
*/
export const solidProfileSchema: Schema = {
type: "Schema",
shapes: [
{
id: "https://shaperepo.com/schemas/solidProfile#SolidProfileShape",
type: "ShapeDecl",
shapeExpr: {
type: "Shape",
expression: {
type: "EachOf",
expressions: [
{
type: "TripleConstraint",
predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
valueExpr: {
type: "NodeConstraint",
values: ["http://schema.org/Person"],
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "Defines the node as a Person (from Schema.org)",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
valueExpr: {
type: "NodeConstraint",
values: ["http://xmlns.com/foaf/0.1/Person"],
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "Defines the node as a Person (from foaf)",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#fn",
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:
"The formatted name of a person. Example: John Smith",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://xmlns.com/foaf/0.1/name",
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: "An alternate way to define a person's name.",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#hasAddress",
valueExpr:
"https://shaperepo.com/schemas/solidProfile#AddressShape",
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "The person's street address.",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#hasEmail",
valueExpr:
"https://shaperepo.com/schemas/solidProfile#EmailShape",
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "The person's email.",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#hasPhoto",
valueExpr: {
type: "NodeConstraint",
nodeKind: "iri",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "A link to the person's photo",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://xmlns.com/foaf/0.1/img",
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: "Photo link but in string form",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#hasTelephone",
valueExpr:
"https://shaperepo.com/schemas/solidProfile#PhoneNumberShape",
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "Person's telephone number",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#phone",
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:
"An alternative way to define a person's telephone number using a string",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#organization-name",
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:
"The name of the organization with which the person is affiliated",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#role",
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:
"The name of the person's role in their organization",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/auth/acl#trustedApp",
valueExpr:
"https://shaperepo.com/schemas/solidProfile#TrustedAppShape",
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"A list of app origins that are trusted by this user",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/auth/cert#key",
valueExpr:
"https://shaperepo.com/schemas/solidProfile#RSAPublicKeyShape",
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"A list of RSA public keys that are associated with private keys the user holds.",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/ldp#inbox",
valueExpr: {
type: "NodeConstraint",
nodeKind: "iri",
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"The user's LDP inbox to which apps can post notifications",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/pim/space#preferencesFile",
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 user's preferences",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/pim/space#storage",
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 location of a Solid storage server related to this WebId",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/solid/terms#account",
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 user's account",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/solid/terms#privateTypeIndex",
valueExpr: {
type: "NodeConstraint",
nodeKind: "iri",
},
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"A registry of all types used on the user's Pod (for private access only)",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/solid/terms#publicTypeIndex",
valueExpr: {
type: "NodeConstraint",
nodeKind: "iri",
},
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"A registry of all types used on the user's Pod (for public access)",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://xmlns.com/foaf/0.1/knows",
valueExpr:
"https://shaperepo.com/schemas/solidProfile#SolidProfileShape",
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"A list of WebIds for all the people this user knows.",
},
},
],
},
],
},
extra: ["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"],
},
},
{
id: "https://shaperepo.com/schemas/solidProfile#AddressShape",
type: "ShapeDecl",
shapeExpr: {
type: "Shape",
expression: {
type: "EachOf",
expressions: [
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#country-name",
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: "The name of the user's country of residence",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#locality",
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:
"The name of the user's locality (City, Town etc.) of residence",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#postal-code",
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: "The user's postal code",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#region",
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:
"The name of the user's region (State, Province etc.) of residence",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#street-address",
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: "The user's street address",
},
},
],
},
],
},
},
},
{
id: "https://shaperepo.com/schemas/solidProfile#EmailShape",
type: "ShapeDecl",
shapeExpr: {
type: "Shape",
expression: {
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/2006/vcard/ns#Dom",
"http://www.w3.org/2006/vcard/ns#Home",
"http://www.w3.org/2006/vcard/ns#ISDN",
"http://www.w3.org/2006/vcard/ns#Internet",
"http://www.w3.org/2006/vcard/ns#Intl",
"http://www.w3.org/2006/vcard/ns#Label",
"http://www.w3.org/2006/vcard/ns#Parcel",
"http://www.w3.org/2006/vcard/ns#Postal",
"http://www.w3.org/2006/vcard/ns#Pref",
"http://www.w3.org/2006/vcard/ns#Work",
"http://www.w3.org/2006/vcard/ns#X400",
],
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "The type of email.",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#value",
valueExpr: {
type: "NodeConstraint",
nodeKind: "iri",
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"The value of an email as a mailto link (Example <mailto:jane@example.com>)",
},
},
],
},
],
},
extra: ["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"],
},
},
{
id: "https://shaperepo.com/schemas/solidProfile#PhoneNumberShape",
type: "ShapeDecl",
shapeExpr: {
type: "Shape",
expression: {
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/2006/vcard/ns#Dom",
"http://www.w3.org/2006/vcard/ns#Home",
"http://www.w3.org/2006/vcard/ns#ISDN",
"http://www.w3.org/2006/vcard/ns#Internet",
"http://www.w3.org/2006/vcard/ns#Intl",
"http://www.w3.org/2006/vcard/ns#Label",
"http://www.w3.org/2006/vcard/ns#Parcel",
"http://www.w3.org/2006/vcard/ns#Postal",
"http://www.w3.org/2006/vcard/ns#Pref",
"http://www.w3.org/2006/vcard/ns#Work",
"http://www.w3.org/2006/vcard/ns#X400",
],
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "They type of Phone Number",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#value",
valueExpr: {
type: "NodeConstraint",
nodeKind: "iri",
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"The value of a phone number as a tel link (Example <tel:555-555-5555>)",
},
},
],
},
],
},
extra: ["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"],
},
},
{
id: "https://shaperepo.com/schemas/solidProfile#TrustedAppShape",
type: "ShapeDecl",
shapeExpr: {
type: "Shape",
expression: {
type: "EachOf",
expressions: [
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/auth/acl#mode",
valueExpr: {
type: "NodeConstraint",
values: [
"http://www.w3.org/ns/auth/acl#Append",
"http://www.w3.org/ns/auth/acl#Control",
"http://www.w3.org/ns/auth/acl#Read",
"http://www.w3.org/ns/auth/acl#Write",
],
},
min: 1,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "The level of access provided to this origin",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/auth/acl#origin",
valueExpr: {
type: "NodeConstraint",
nodeKind: "iri",
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "The app origin the user trusts",
},
},
],
},
],
},
},
},
{
id: "https://shaperepo.com/schemas/solidProfile#RSAPublicKeyShape",
type: "ShapeDecl",
shapeExpr: {
type: "Shape",
expression: {
type: "EachOf",
expressions: [
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/auth/cert#modulus",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#string",
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "RSA Modulus",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/auth/cert#exponent",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#integer",
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "RSA Exponent",
},
},
],
},
],
},
},
},
],
};

@ -0,0 +1,71 @@
import { ShapeType } from "@ldo/ldo";
import { solidProfileSchema } from "./solidProfile.schema";
import { solidProfileContext } from "./solidProfile.context";
import {
SolidProfileShape,
AddressShape,
EmailShape,
PhoneNumberShape,
TrustedAppShape,
RSAPublicKeyShape,
} from "./solidProfile.typings";
/**
* =============================================================================
* LDO ShapeTypes solidProfile
* =============================================================================
*/
/**
* SolidProfileShape ShapeType
*/
export const SolidProfileShapeShapeType: ShapeType<SolidProfileShape> = {
schema: solidProfileSchema,
shape: "https://shaperepo.com/schemas/solidProfile#SolidProfileShape",
context: solidProfileContext,
};
/**
* AddressShape ShapeType
*/
export const AddressShapeShapeType: ShapeType<AddressShape> = {
schema: solidProfileSchema,
shape: "https://shaperepo.com/schemas/solidProfile#AddressShape",
context: solidProfileContext,
};
/**
* EmailShape ShapeType
*/
export const EmailShapeShapeType: ShapeType<EmailShape> = {
schema: solidProfileSchema,
shape: "https://shaperepo.com/schemas/solidProfile#EmailShape",
context: solidProfileContext,
};
/**
* PhoneNumberShape ShapeType
*/
export const PhoneNumberShapeShapeType: ShapeType<PhoneNumberShape> = {
schema: solidProfileSchema,
shape: "https://shaperepo.com/schemas/solidProfile#PhoneNumberShape",
context: solidProfileContext,
};
/**
* TrustedAppShape ShapeType
*/
export const TrustedAppShapeShapeType: ShapeType<TrustedAppShape> = {
schema: solidProfileSchema,
shape: "https://shaperepo.com/schemas/solidProfile#TrustedAppShape",
context: solidProfileContext,
};
/**
* RSAPublicKeyShape ShapeType
*/
export const RSAPublicKeyShapeShapeType: ShapeType<RSAPublicKeyShape> = {
schema: solidProfileSchema,
shape: "https://shaperepo.com/schemas/solidProfile#RSAPublicKeyShape",
context: solidProfileContext,
};

@ -0,0 +1,293 @@
import { LdoJsonldContext, LdSet } from "@ldo/ldo";
/**
* =============================================================================
* Typescript Typings for solidProfile
* =============================================================================
*/
/**
* SolidProfileShape Type
*/
export interface SolidProfileShape {
"@id"?: string;
"@context"?: LdoJsonldContext;
/**
* Defines the node as a Person (from Schema.org) | Defines the node as a Person (from foaf)
*/
type: LdSet<
| {
"@id": "Person";
}
| {
"@id": "Person2";
}
>;
/**
* The formatted name of a person. Example: John Smith
*/
fn?: string;
/**
* An alternate way to define a person's name.
*/
name?: string;
/**
* The person's street address.
*/
hasAddress?: LdSet<AddressShape>;
/**
* The person's email.
*/
hasEmail?: LdSet<EmailShape>;
/**
* A link to the person's photo
*/
hasPhoto?: {
"@id": string;
};
/**
* Photo link but in string form
*/
img?: string;
/**
* Person's telephone number
*/
hasTelephone?: LdSet<PhoneNumberShape>;
/**
* An alternative way to define a person's telephone number using a string
*/
phone?: string;
/**
* The name of the organization with which the person is affiliated
*/
organizationName?: string;
/**
* The name of the person's role in their organization
*/
role?: string;
/**
* A list of app origins that are trusted by this user
*/
trustedApp?: LdSet<TrustedAppShape>;
/**
* A list of RSA public keys that are associated with private keys the user holds.
*/
key?: LdSet<RSAPublicKeyShape>;
/**
* The user's LDP inbox to which apps can post notifications
*/
inbox: {
"@id": string;
};
/**
* The user's preferences
*/
preferencesFile?: {
"@id": string;
};
/**
* The location of a Solid storage server related to this WebId
*/
storage?: LdSet<{
"@id": string;
}>;
/**
* The user's account
*/
account?: {
"@id": string;
};
/**
* A registry of all types used on the user's Pod (for private access only)
*/
privateTypeIndex?: LdSet<{
"@id": string;
}>;
/**
* A registry of all types used on the user's Pod (for public access)
*/
publicTypeIndex?: LdSet<{
"@id": string;
}>;
/**
* A list of WebIds for all the people this user knows.
*/
knows?: LdSet<SolidProfileShape>;
}
/**
* AddressShape Type
*/
export interface AddressShape {
"@id"?: string;
"@context"?: LdoJsonldContext;
/**
* The name of the user's country of residence
*/
countryName?: string;
/**
* The name of the user's locality (City, Town etc.) of residence
*/
locality?: string;
/**
* The user's postal code
*/
postalCode?: string;
/**
* The name of the user's region (State, Province etc.) of residence
*/
region?: string;
/**
* The user's street address
*/
streetAddress?: string;
}
/**
* EmailShape Type
*/
export interface EmailShape {
"@id"?: string;
"@context"?: LdoJsonldContext;
/**
* The type of email.
*/
type?:
| {
"@id": "Dom";
}
| {
"@id": "Home";
}
| {
"@id": "ISDN";
}
| {
"@id": "Internet";
}
| {
"@id": "Intl";
}
| {
"@id": "Label";
}
| {
"@id": "Parcel";
}
| {
"@id": "Postal";
}
| {
"@id": "Pref";
}
| {
"@id": "Work";
}
| {
"@id": "X400";
};
/**
* The value of an email as a mailto link (Example <mailto:jane@example.com>)
*/
value: {
"@id": string;
};
}
/**
* PhoneNumberShape Type
*/
export interface PhoneNumberShape {
"@id"?: string;
"@context"?: LdoJsonldContext;
/**
* They type of Phone Number
*/
type?:
| {
"@id": "Dom";
}
| {
"@id": "Home";
}
| {
"@id": "ISDN";
}
| {
"@id": "Internet";
}
| {
"@id": "Intl";
}
| {
"@id": "Label";
}
| {
"@id": "Parcel";
}
| {
"@id": "Postal";
}
| {
"@id": "Pref";
}
| {
"@id": "Work";
}
| {
"@id": "X400";
};
/**
* The value of a phone number as a tel link (Example <tel:555-555-5555>)
*/
value: {
"@id": string;
};
}
/**
* TrustedAppShape Type
*/
export interface TrustedAppShape {
"@id"?: string;
"@context"?: LdoJsonldContext;
/**
* The level of access provided to this origin
*/
mode: LdSet<
| {
"@id": "Append";
}
| {
"@id": "Control";
}
| {
"@id": "Read";
}
| {
"@id": "Write";
}
>;
/**
* The app origin the user trusts
*/
origin: {
"@id": string;
};
}
/**
* RSAPublicKeyShape Type
*/
export interface RSAPublicKeyShape {
"@id"?: string;
"@context"?: LdoJsonldContext;
/**
* RSA Modulus
*/
modulus: string;
/**
* RSA Exponent
*/
exponent: number;
}

@ -0,0 +1,121 @@
PREFIX srs: <https://shaperepo.com/schemas/solidProfile#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX schem: <http://schema.org/>
PREFIX vcard: <http://www.w3.org/2006/vcard/ns#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX acl: <http://www.w3.org/ns/auth/acl#>
PREFIX cert: <http://www.w3.org/ns/auth/cert#>
PREFIX ldp: <http://www.w3.org/ns/ldp#>
PREFIX sp: <http://www.w3.org/ns/pim/space#>
PREFIX solid: <http://www.w3.org/ns/solid/terms#>
srs:SolidProfileShape EXTRA a {
a [ schem:Person ]
// rdfs:comment "Defines the node as a Person (from Schema.org)" ;
a [ foaf:Person ]
// rdfs:comment "Defines the node as a Person (from foaf)" ;
vcard:fn xsd:string ?
// rdfs:comment "The formatted name of a person. Example: John Smith" ;
foaf:name xsd:string ?
// rdfs:comment "An alternate way to define a person's name." ;
vcard:hasAddress @srs:AddressShape *
// rdfs:comment "The person's street address." ;
vcard:hasEmail @srs:EmailShape *
// rdfs:comment "The person's email." ;
vcard:hasPhoto IRI ?
// rdfs:comment "A link to the person's photo" ;
foaf:img xsd:string ?
// rdfs:comment "Photo link but in string form" ;
vcard:hasTelephone @srs:PhoneNumberShape *
// rdfs:comment "Person's telephone number" ;
vcard:phone xsd:string ?
// rdfs:comment "An alternative way to define a person's telephone number using a string" ;
vcard:organization-name xsd:string ?
// rdfs:comment "The name of the organization with which the person is affiliated" ;
vcard:role xsd:string ?
// rdfs:comment "The name of the person's role in their organization" ;
acl:trustedApp @srs:TrustedAppShape *
// rdfs:comment "A list of app origins that are trusted by this user" ;
cert:key @srs:RSAPublicKeyShape *
// rdfs:comment "A list of RSA public keys that are associated with private keys the user holds." ;
ldp:inbox IRI
// rdfs:comment "The user's LDP inbox to which apps can post notifications" ;
sp:preferencesFile IRI ?
// rdfs:comment "The user's preferences" ;
sp:storage IRI *
// rdfs:comment "The location of a Solid storage server related to this WebId" ;
solid:account IRI ?
// rdfs:comment "The user's account" ;
solid:privateTypeIndex IRI *
// rdfs:comment "A registry of all types used on the user's Pod (for private access only)" ;
solid:publicTypeIndex IRI *
// rdfs:comment "A registry of all types used on the user's Pod (for public access)" ;
foaf:knows @srs:SolidProfileShape *
// rdfs:comment "A list of WebIds for all the people this user knows." ;
}
srs:AddressShape {
vcard:country-name xsd:string ?
// rdfs:comment "The name of the user's country of residence" ;
vcard:locality xsd:string ?
// rdfs:comment "The name of the user's locality (City, Town etc.) of residence" ;
vcard:postal-code xsd:string ?
// rdfs:comment "The user's postal code" ;
vcard:region xsd:string ?
// rdfs:comment "The name of the user's region (State, Province etc.) of residence" ;
vcard:street-address xsd:string ?
// rdfs:comment "The user's street address" ;
}
srs:EmailShape EXTRA a {
a [
vcard:Dom
vcard:Home
vcard:ISDN
vcard:Internet
vcard:Intl
vcard:Label
vcard:Parcel
vcard:Postal
vcard:Pref
vcard:Work
vcard:X400
] ?
// rdfs:comment "The type of email." ;
vcard:value IRI
// rdfs:comment "The value of an email as a mailto link (Example <mailto:jane@example.com>)" ;
}
srs:PhoneNumberShape EXTRA a {
a [
vcard:Dom
vcard:Home
vcard:ISDN
vcard:Internet
vcard:Intl
vcard:Label
vcard:Parcel
vcard:Postal
vcard:Pref
vcard:Work
vcard:X400
] ?
// rdfs:comment "They type of Phone Number" ;
vcard:value IRI
// rdfs:comment "The value of a phone number as a tel link (Example <tel:555-555-5555>)" ;
}
srs:TrustedAppShape {
acl:mode [acl:Append acl:Control acl:Read acl:Write] +
// rdfs:comment "The level of access provided to this origin" ;
acl:origin IRI
// rdfs:comment "The app origin the user trusts"
}
srs:RSAPublicKeyShape {
cert:modulus xsd:string
// rdfs:comment "RSA Modulus" ;
cert:exponent xsd:integer
// rdfs:comment "RSA Exponent" ;
}

@ -0,0 +1,42 @@
import type { ResourceInfo } from "@ldo/test-solid-server";
export const BASE_CONTAINER = "http://localhost:3005/test-container/";
export const MAIN_PROFILE_URI = `${BASE_CONTAINER}mainProfile.ttl`;
export const MAIN_PROFILE_SUBJECT = `${MAIN_PROFILE_URI}#me`;
export const OTHER_PROFILE_URI = `${BASE_CONTAINER}otherProfile.ttl`;
export const OTHER_PROFILE_SUBJECT = `${OTHER_PROFILE_URI}#me`;
export const linkTraversalData: ResourceInfo = {
slug: "test-container/",
isContainer: true,
contains: [
{
slug: "mainProfile.ttl",
isContainer: false,
mimeType: "text/ttl",
data: `
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix : <#> .
:me a foaf:Person ;
foaf:name "Main User" ;
foaf:mbox <mailto:main@example.org> ;
foaf:knows <http://localhost:3005/test-container/otherProfile.ttl#me> .
`,
},
{
slug: "otherProfile.ttl",
isContainer: false,
mimeType: "text/ttl",
data: `
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix : <#> .
:me a foaf:Person ;
foaf:name "Other User" ;
foaf:mbox <mailto:other@example.org> ;
foaf:knows <http://localhost:3005/test-container/mainProfile.ttl#me> .
`,
},
],
};

@ -1,101 +1,51 @@
import type { App } from "@solid/community-server"; import type { ConnectedLdoDataset } from "../src/ConnectedLdoDataset";
import type { ConnectedLdoDataset } from "../src"; import { createConnectedLdoDataset } from "../src";
import { ROOT_CONTAINER, WEB_ID, createApp } from "./solidServer.helper"; import {
import { generateAuthFetch } from "./authFetch.helper"; solidConnectedPlugin,
import type { SolidConnectedPlugin } from "@ldo/connected-solid"; type SolidConnectedPlugin,
} from "@ldo/connected-solid";
import { setupServer } from "@ldo/test-solid-server";
import {
linkTraversalData,
MAIN_PROFILE_SUBJECT,
MAIN_PROFILE_URI,
OTHER_PROFILE_URI,
} from "./LinkTraversalData";
import { SolidProfileShapeShapeType } from "./.ldo/solidProfile.shapeTypes";
describe("Link Traversal", () => { describe("Link Traversal", () => {
let app: App; // eslint-disable-next-line @typescript-eslint/ban-ts-comment
let authFetch: typeof fetch; // @ts-ignore
let fetchMock: jest.Mock<
Promise<Response>,
[input: RequestInfo | URL, init?: RequestInit | undefined]
>;
let solidLdoDataset: ConnectedLdoDataset<SolidConnectedPlugin[]>; let solidLdoDataset: ConnectedLdoDataset<SolidConnectedPlugin[]>;
let previousJestId: string | undefined; const s = setupServer(3005, linkTraversalData);
let previousNodeEnv: string | undefined;
beforeAll(async () => {
// Remove Jest ID so that community solid server doesn't use the Jest Import
previousJestId = process.env.JEST_WORKER_ID;
previousNodeEnv = process.env.NODE_ENV;
delete process.env.JEST_WORKER_ID;
process.env.NODE_ENV = "other_test";
// Start up the server
app = await createApp();
await app.start();
authFetch = await generateAuthFetch();
});
afterAll(async () => {
app.stop();
process.env.JEST_WORKER_ID = previousJestId;
process.env.NODE_ENV = previousNodeEnv;
const testDataPath = path.join(__dirname, "./data");
await fs.rm(testDataPath, { recursive: true, force: true });
});
beforeEach(async () => { beforeEach(async () => {
fetchMock = jest.fn(authFetch); // eslint-disable-next-line @typescript-eslint/ban-ts-comment
solidLdoDataset = createSolidLdoDataset(); // @ts-ignore
solidLdoDataset.setContext("solid", { fetch: fetchMock }); solidLdoDataset = createConnectedLdoDataset([solidConnectedPlugin]);
// Create a new document called sample.ttl solidLdoDataset.setContext("solid", { fetch: s.fetchMock });
await authFetch(ROOT_CONTAINER, {
method: "POST",
headers: {
link: '<http://www.w3.org/ns/ldp#Container>; rel="type"',
slug: TEST_CONTAINER_SLUG,
},
});
await authFetch(TEST_CONTAINER_ACL_URI, {
method: "PUT",
headers: {
"content-type": "text/turtle",
},
body: TEST_CONTAINER_ACL,
});
await Promise.all([
authFetch(TEST_CONTAINER_URI, {
method: "POST",
headers: { "content-type": "text/turtle", slug: "sample.ttl" },
body: SPIDER_MAN_TTL,
}),
authFetch(TEST_CONTAINER_URI, {
method: "POST",
headers: { "content-type": "text/plain", slug: "sample.txt" },
body: "some text.",
}),
authFetch(TEST_CONTAINER_URI, {
method: "POST",
headers: { "content-type": "text/turtle", slug: "profile.ttl" },
body: SAMPLE_PROFILE_TTL,
}),
]);
}); });
afterEach(async () => { it("does a simple run to traverse data", async () => {
await Promise.all([ const mainProfileResource = solidLdoDataset.getResource(MAIN_PROFILE_URI);
authFetch(SAMPLE_DATA_URI, { const data = await solidLdoDataset
method: "DELETE", .usingType(SolidProfileShapeShapeType)
}), .startLinkQuery(mainProfileResource, MAIN_PROFILE_SUBJECT, {
authFetch(SAMPLE2_DATA_URI, { name: true,
method: "DELETE", knows: {
}), name: true,
authFetch(SAMPLE_BINARY_URI, { },
method: "DELETE", })
}), .run();
authFetch(SAMPLE2_BINARY_URI, { const resourceUris = solidLdoDataset
method: "DELETE", .getResources()
}), .map((resource) => resource.uri);
authFetch(SAMPLE_PROFILE_URI, { console.log(resourceUris);
method: "DELETE", expect(resourceUris.length).toBe(2);
}), expect(resourceUris).toContain(MAIN_PROFILE_URI);
authFetch(SAMPLE_CONTAINER_URI, { expect(resourceUris).toContain(OTHER_PROFILE_URI);
method: "DELETE", expect(data.name).toBe("Main User");
}), expect(data.knows?.toArray()[0].name).toBe("Other User");
]);
await authFetch(TEST_CONTAINER_URI, {
method: "DELETE",
});
}); });
}); });

@ -1,112 +0,0 @@
import type { KeyPair } from "@inrupt/solid-client-authn-core";
import {
buildAuthenticatedFetch,
createDpopHeader,
generateDpopKeyPair,
} from "@inrupt/solid-client-authn-core";
import fetch from "cross-fetch";
const config = {
podName: process.env.USER_NAME || "example",
email: process.env.EMAIL || "hello@example.com",
password: process.env.PASSWORD || "abc123",
};
async function getAuthorization(): Promise<string> {
// First we request the account API controls to find out where we can log in
const indexResponse = await fetch("http://localhost:3001/.account/");
const { controls } = await indexResponse.json();
// And then we log in to the account API
const response = await fetch(controls.password.login, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
email: config.email,
password: config.password,
}),
});
// This authorization value will be used to authenticate in the next step
const result = await response.json();
return result.authorization;
}
async function getSecret(
authorization: string,
): Promise<{ id: string; secret: string; resource: string }> {
// Now that we are logged in, we need to request the updated controls from the server.
// These will now have more values than in the previous example.
const indexResponse = await fetch("http://localhost:3001/.account/", {
headers: { authorization: `CSS-Account-Token ${authorization}` },
});
const { controls } = await indexResponse.json();
// Here we request the server to generate a token on our account
const response = await fetch(controls.account.clientCredentials, {
method: "POST",
headers: {
authorization: `CSS-Account-Token ${authorization}`,
"content-type": "application/json",
},
// The name field will be used when generating the ID of your token.
// The WebID field determines which WebID you will identify as when using the token.
// Only WebIDs linked to your account can be used.
body: JSON.stringify({
name: "my-token",
webId: `http://localhost:3001/${config.podName}/profile/card#me`,
}),
});
// These are the identifier and secret of your token.
// Store the secret somewhere safe as there is no way to request it again from the server!
// The `resource` value can be used to delete the token at a later point in time.
const response2 = await response.json();
return response2;
}
async function getAccessToken(
id: string,
secret: string,
): Promise<{ accessToken: string; dpopKey: KeyPair }> {
try {
// A key pair is needed for encryption.
// This function from `solid-client-authn` generates such a pair for you.
const dpopKey = await generateDpopKeyPair();
// These are the ID and secret generated in the previous step.
// Both the ID and the secret need to be form-encoded.
const authString = `${encodeURIComponent(id)}:${encodeURIComponent(
secret,
)}`;
// This URL can be found by looking at the "token_endpoint" field at
// http://localhost:3001/.well-known/openid-configuration
// if your server is hosted at http://localhost:3000/.
const tokenUrl = "http://localhost:3001/.oidc/token";
const response = await fetch(tokenUrl, {
method: "POST",
headers: {
// The header needs to be in base64 encoding.
authorization: `Basic ${Buffer.from(authString).toString("base64")}`,
"content-type": "application/x-www-form-urlencoded",
dpop: await createDpopHeader(tokenUrl, "POST", dpopKey),
},
body: "grant_type=client_credentials&scope=webid",
});
// This is the Access token that will be used to do an authenticated request to the server.
// The JSON also contains an "expires_in" field in seconds,
// which you can use to know when you need request a new Access token.
const response2 = await response.json();
return { accessToken: response2.access_token, dpopKey };
} catch (err) {
console.error(err);
throw err;
}
}
export async function generateAuthFetch() {
const authorization = await getAuthorization();
const { id, secret } = await getSecret(authorization);
const { accessToken, dpopKey } = await getAccessToken(id, secret);
return await buildAuthenticatedFetch(accessToken, { dpopKey });
}

@ -1,44 +0,0 @@
{
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^7.0.0/components/context.jsonld",
"import": [
"css:config/app/init/initialize-root.json",
"css:config/app/main/default.json",
"css:config/app/variables/default.json",
"css:config/http/handler/default.json",
"css:config/http/middleware/default.json",
"css:config/http/notifications/webhooks.json",
"css:config/http/server-factory/http.json",
"css:config/http/static/default.json",
"css:config/identity/access/public.json",
"css:config/identity/email/default.json",
"css:config/identity/handler/no-accounts.json",
"css:config/identity/oidc/default.json",
"css:config/identity/ownership/token.json",
"css:config/identity/pod/static.json",
"css:config/ldp/authentication/dpop-bearer.json",
"css:config/ldp/authorization/webacl.json",
"css:config/ldp/handler/default.json",
"css:config/ldp/metadata-parser/default.json",
"css:config/ldp/metadata-writer/default.json",
"css:config/ldp/modes/default.json",
"css:config/storage/backend/file.json",
"css:config/storage/key-value/resource-store.json",
"css:config/storage/location/root.json",
"css:config/storage/middleware/default.json",
"css:config/util/auxiliary/acl.json",
"css:config/util/identifiers/suffix.json",
"css:config/util/index/default.json",
"css:config/util/logging/winston.json",
"css:config/util/representation-conversion/default.json",
"css:config/util/resource-locker/file.json",
"css:config/util/variables/default.json"
],
"@graph": [
{
"comment": [
"A Solid server that stores its resources on disk and uses WAC for authorization.",
"No registration and the root container is initialized to allow full access for everyone so make sure to change this."
]
}
]
}

@ -1,43 +0,0 @@
{
"@context": [
"https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^7.0.0/components/context.jsonld"
],
"import": [
"css:config/app/init/static-root.json",
"css:config/app/main/default.json",
"css:config/app/variables/default.json",
"css:config/http/handler/default.json",
"css:config/http/middleware/default.json",
"css:config/http/notifications/all.json",
"css:config/http/server-factory/http.json",
"css:config/http/static/default.json",
"css:config/identity/access/public.json",
"css:config/identity/email/default.json",
"css:config/identity/handler/default.json",
"css:config/identity/oidc/default.json",
"css:config/identity/ownership/token.json",
"css:config/identity/pod/static.json",
"css:config/ldp/authentication/dpop-bearer.json",
"css:config/ldp/authorization/webacl.json",
"css:config/ldp/handler/default.json",
"css:config/ldp/metadata-parser/default.json",
"css:config/ldp/metadata-writer/default.json",
"css:config/ldp/modes/default.json",
"css:config/storage/backend/memory.json",
"css:config/storage/key-value/resource-store.json",
"css:config/storage/location/pod.json",
"css:config/storage/middleware/default.json",
"css:config/util/auxiliary/acl.json",
"css:config/util/identifiers/suffix.json",
"css:config/util/index/default.json",
"css:config/util/logging/winston.json",
"css:config/util/representation-conversion/default.json",
"css:config/util/resource-locker/memory.json",
"css:config/util/variables/default.json"
],
"@graph": [
{
"comment": "A Solid server that stores its resources on disk and uses WAC for authorization."
}
]
}

@ -1,9 +0,0 @@
[
{
"email": "hello@example.com",
"password": "abc123",
"pods": [
{ "name": "example" }
]
}
]

@ -1,3 +0,0 @@
import { config } from "dotenv";
config();

@ -1,42 +0,0 @@
// Taken from https://github.com/comunica/comunica/blob/b237be4265c353a62a876187d9e21e3bc05123a3/engines/query-sparql/test/QuerySparql-solid-test.ts#L9
import * as path from "path";
import type { App } from "@solid/community-server";
import { AppRunner, resolveModulePath } from "@solid/community-server";
import "jest-rdf";
import type { SolidContainerUri } from "../src";
export const SERVER_DOMAIN = process.env.SERVER || "http://localhost:3001/";
export const ROOT_ROUTE = process.env.ROOT_CONTAINER || "";
export const ROOT_CONTAINER =
`${SERVER_DOMAIN}${ROOT_ROUTE}` as SolidContainerUri;
export const WEB_ID =
process.env.WEB_ID || `${SERVER_DOMAIN}example/profile/card#me`;
// Use an increased timeout, since the CSS server takes too much setup time.
jest.setTimeout(40_000);
export async function createApp(customConfigPath?: string): Promise<App> {
if (process.env.SERVER) {
return {
start: () => {},
stop: () => {},
} as App;
}
const appRunner = new AppRunner();
return appRunner.create({
loaderProperties: {
mainModulePath: resolveModulePath(""),
typeChecking: false,
},
config: customConfigPath ?? resolveModulePath("config/file-root.json"),
variableBindings: {},
shorthand: {
port: 3_001,
loggingLevel: "off",
seedConfig: path.join(__dirname, "configs", "solid-css-seed.json"),
rootFilePath: path.join(__dirname, "./data"),
},
});
}

@ -1,3 +1,17 @@
# @ldo/test-solid-server # @ldo/test-solid-server
This is a reusable Solid Server to be used in Jest integration tests. This is a reusable Solid Server to be used in Jest integration tests.
## Setup
Install cross-env
```
npm i --save-dev cross-env
```
Use the following to run your tests
```
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --coverage",
```

@ -81,7 +81,7 @@ async function getAccessToken(
secret, secret,
)}`; )}`;
// This URL can be found by looking at the "token_endpoint" field at // This URL can be found by looking at the "token_endpoint" field at
// http://localhost:3001/.well-known/openid-configuration // http://localhost:PORT/.well-known/openid-configuration
// if your server is hosted at http://localhost:3000/. // if your server is hosted at http://localhost:3000/.
const tokenUrl = `http://localhost:${port}/.oidc/token`; const tokenUrl = `http://localhost:${port}/.oidc/token`;
const response = await fetch(tokenUrl, { const response = await fetch(tokenUrl, {

Loading…
Cancel
Save