commit
ff92c8b67a
@ -1,4 +1,4 @@ |
||||
{ |
||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json", |
||||
"version": "1.0.0-alpha.8" |
||||
"version": "1.0.0-alpha.9" |
||||
} |
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,3 +0,0 @@ |
||||
import { config } from "dotenv"; |
||||
|
||||
config(); |
@ -0,0 +1,43 @@ |
||||
import type { LdoBase, ShapeType } from "@ldo/ldo"; |
||||
import { LdoBuilder } from "@ldo/ldo"; |
||||
import type { IConnectedLdoBuilder } from "./types/IConnectedLdoBuilder"; |
||||
import type { JsonldDatasetProxyBuilder } from "@ldo/jsonld-dataset-proxy"; |
||||
import type { SubjectNode } from "@ldo/rdf-utils"; |
||||
import type { LQInput } from "./types/ILinkQuery"; |
||||
import { ResourceLinkQuery } from "./linkTraversal/ResourceLinkQuery"; |
||||
import type { ConnectedPlugin } from "./types/ConnectedPlugin"; |
||||
import type { IConnectedLdoDataset } from "./types/IConnectedLdoDataset"; |
||||
|
||||
export class ConnectedLdoBuilder< |
||||
Type extends LdoBase, |
||||
Plugins extends ConnectedPlugin[], |
||||
> |
||||
extends LdoBuilder<Type> |
||||
implements IConnectedLdoBuilder<Type, Plugins> |
||||
{ |
||||
protected parentDataset: IConnectedLdoDataset<Plugins>; |
||||
|
||||
constructor( |
||||
parentDataset: IConnectedLdoDataset<Plugins>, |
||||
jsonldDatasetProxyBuilder: JsonldDatasetProxyBuilder, |
||||
shapeType: ShapeType<Type>, |
||||
) { |
||||
super(jsonldDatasetProxyBuilder, shapeType); |
||||
this.parentDataset = parentDataset; |
||||
} |
||||
|
||||
startLinkQuery<Input extends LQInput<Type>>( |
||||
startingResource: Plugins[number]["types"]["resource"], |
||||
startingSubject: SubjectNode | string, |
||||
linkQueryInput: Input, |
||||
): ResourceLinkQuery<Type, Input, Plugins> { |
||||
return new ResourceLinkQuery( |
||||
this.parentDataset, |
||||
this.shapeType, |
||||
this, |
||||
startingResource, |
||||
startingSubject, |
||||
linkQueryInput, |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,287 @@ |
||||
import type { LdoBase, ShapeType } from "@ldo/ldo"; |
||||
import type { |
||||
ExpandDeep, |
||||
ILinkQuery, |
||||
LQInput, |
||||
LQReturn, |
||||
} from "../types/ILinkQuery"; |
||||
import type { ConnectedPlugin } from "../types/ConnectedPlugin"; |
||||
import type { SubjectNode } from "@ldo/rdf-utils"; |
||||
import { exploreLinks } from "./exploreLinks"; |
||||
import type { IConnectedLdoDataset } from "../types/IConnectedLdoDataset"; |
||||
import type { IConnectedLdoBuilder } from "../types/IConnectedLdoBuilder"; |
||||
import { v4 } from "uuid"; |
||||
import type { nodeEventListener } from "@ldo/subscribable-dataset"; |
||||
import type { Quad } from "@rdfjs/types"; |
||||
|
||||
/** |
||||
* Represents a query over multiple datasources and constituting muliple |
||||
* resources. |
||||
* |
||||
* @example |
||||
* ```typescript
|
||||
* import { ProfileShapeType } from "./.ldo/Profile.shapeType.ts"; |
||||
* |
||||
* // Create a link query
|
||||
* const linkQuery = ldoDataset |
||||
* .usingType(ProfileShapeType) |
||||
* .startLinkQuery( |
||||
* "http://example.com/profile/card", |
||||
* "http://example.com/profile/card#me", |
||||
* { |
||||
* name: true, |
||||
* knows: { |
||||
* name: true, |
||||
* }, |
||||
* }, |
||||
* } |
||||
* ); |
||||
* // Susbscribe to this link query, automaticically updating the dataset when
|
||||
* // something from the link query is changed.
|
||||
* await linkQuery.subscribe(); |
||||
* ``` |
||||
*/ |
||||
export class ResourceLinkQuery< |
||||
Type extends LdoBase, |
||||
QueryInput extends LQInput<Type>, |
||||
Plugins extends ConnectedPlugin[], |
||||
> implements ILinkQuery<Type, QueryInput> |
||||
{ |
||||
protected previousTransactionId: string = "INIT"; |
||||
|
||||
// Resource Subscriptions uri -> unsubscribeId
|
||||
protected activeResourceSubscriptions: Record<string, string> = {}; |
||||
// Unsubscribe IDs for this ResourceLinkQuery
|
||||
protected thisUnsubscribeIds = new Set<string>(); |
||||
|
||||
protected curOnDataChanged: nodeEventListener<Quad> | undefined; |
||||
|
||||
protected resourcesWithSubscriptionInProgress: Record< |
||||
string, |
||||
Promise<void> | undefined |
||||
> = {}; |
||||
|
||||
/** |
||||
* @internal |
||||
* @param parentDataset The dataset for which this link query is a part |
||||
* @param shapeType A ShapeType for the link query to follow |
||||
* @param ldoBuilder An LdoBuilder associated with the dataset |
||||
* @param startingResource The resource to explore first in the link query |
||||
* @param startingSubject The starting point of the link query |
||||
* @param linkQueryInput A definition of the link query |
||||
*/ |
||||
constructor( |
||||
protected parentDataset: IConnectedLdoDataset<Plugins>, |
||||
protected shapeType: ShapeType<Type>, |
||||
protected ldoBuilder: IConnectedLdoBuilder<Type, Plugins>, |
||||
protected startingResource: Plugins[number]["types"]["resource"], |
||||
protected startingSubject: SubjectNode | string, |
||||
protected linkQueryInput: QueryInput, |
||||
) {} |
||||
|
||||
/** |
||||
* Runs this link query, returning the result |
||||
* @param options Options for how to run the link query |
||||
* @returns A subset of the ShapeType as defined by the LinkQuery |
||||
* |
||||
* @example |
||||
* ``` |
||||
* import { ProfileShapeType } from "./.ldo/Profile.shapeType.ts"; |
||||
* |
||||
* // Create a link query
|
||||
* const linkQuery = ldoDataset |
||||
* .usingType(ProfileShapeType) |
||||
* .startLinkQuery( |
||||
* "http://example.com/profile/card", |
||||
* "http://example.com/profile/card#me", |
||||
* { |
||||
* name: true, |
||||
* knows: { |
||||
* name: true, |
||||
* }, |
||||
* }, |
||||
* } |
||||
* ); |
||||
* // Susbscribe to this link query, automaticically updating the dataset when
|
||||
* // something from the link query is changed.
|
||||
* const result = await linkQuery.read(); |
||||
* console.log(result.name); |
||||
* result.knows.forEach((person) => console.log(person.name)); |
||||
* // The following will type-error. Despite "phone" existing on a Profile,
|
||||
* // it was not covered by the link query.
|
||||
* console.log(result.phone); |
||||
* ``` |
||||
*/ |
||||
async run(options?: { |
||||
reload?: boolean; |
||||
}): Promise<ExpandDeep<LQReturn<Type, QueryInput>>> { |
||||
await exploreLinks( |
||||
this.parentDataset, |
||||
this.shapeType, |
||||
this.startingResource, |
||||
this.startingSubject, |
||||
this.linkQueryInput, |
||||
{ shouldRefreshResources: options?.reload }, |
||||
); |
||||
return this.fromSubject(); |
||||
} |
||||
|
||||
/** |
||||
* Subscribes to the data defined by the link query, updating the dataset if |
||||
* any changes are made. |
||||
* @returns An unsubscribeId |
||||
* |
||||
* @example |
||||
* ``` |
||||
* import { ProfileShapeType } from "./.ldo/Profile.shapeType.ts"; |
||||
* |
||||
* // Create a link query
|
||||
* const linkQuery = ldoDataset |
||||
* .usingType(ProfileShapeType) |
||||
* .startLinkQuery( |
||||
* "http://example.com/profile/card", |
||||
* "http://example.com/profile/card#me", |
||||
* { |
||||
* name: true, |
||||
* knows: { |
||||
* name: true, |
||||
* }, |
||||
* }, |
||||
* } |
||||
* ); |
||||
* // Susbscribe to this link query, automaticically updating the dataset when
|
||||
* // something from the link query is changed.
|
||||
* const unsubscribeId = await linkQuery.subscribe(); |
||||
* |
||||
* // Now, let's imagine the following triple was added to
|
||||
* "http://example.com/profile/card": |
||||
* <http://example.com/profile/card#me> <http://xmlns.com/foaf/0.1/knows> <http://example2.com/profile/card#me> |
||||
* Because you're subscribed, the dataset will automatically be updated. |
||||
* |
||||
* // End subscription
|
||||
* linkQuery.unsubscribe(unsubscribeId); |
||||
* ``` |
||||
*/ |
||||
async subscribe(): Promise<string> { |
||||
const subscriptionId = v4(); |
||||
this.thisUnsubscribeIds.add(subscriptionId); |
||||
// If there's already a registered onDataChange, we don't need to make a new
|
||||
// on for this new subscription
|
||||
if (this.curOnDataChanged) { |
||||
return subscriptionId; |
||||
} |
||||
this.curOnDataChanged = async ( |
||||
_changes, |
||||
transactionId: string, |
||||
_triggering, |
||||
) => { |
||||
// Set a transaction Id, so that we only trigger one re-render
|
||||
if (transactionId === this.previousTransactionId) return; |
||||
this.previousTransactionId = transactionId; |
||||
// Remove previous registration
|
||||
this.parentDataset.removeListenerFromAllEvents(this.curOnDataChanged!); |
||||
|
||||
// Explore the links, with a subscription to re-explore the links if any
|
||||
// covered information changes
|
||||
const resourcesToUnsubscribeFrom = new Set( |
||||
Object.keys(this.activeResourceSubscriptions), |
||||
); |
||||
|
||||
// Only add the listeners if we're currently subscribed
|
||||
const exploreOptions = this.curOnDataChanged |
||||
? { |
||||
onCoveredDataChanged: this.curOnDataChanged, |
||||
onResourceEncountered: async (resource) => { |
||||
// Wait for the the in progress registration to complete. Once it
|
||||
// is complete, you're subscribed, so we can remove this from the
|
||||
// resources to unsubscribe from.
|
||||
if (this.resourcesWithSubscriptionInProgress[resource.uri]) { |
||||
await this.resourcesWithSubscriptionInProgress[resource.uri]; |
||||
resourcesToUnsubscribeFrom.delete(resource.uri); |
||||
return; |
||||
} |
||||
// No need to do anything if we're already subscribed
|
||||
if (resourcesToUnsubscribeFrom.has(resource.uri)) { |
||||
resourcesToUnsubscribeFrom.delete(resource.uri); |
||||
return; |
||||
} |
||||
// Otherwise begin the subscription
|
||||
let resolve; |
||||
this.resourcesWithSubscriptionInProgress[resource.uri] = |
||||
new Promise<void>((res) => { |
||||
resolve = res; |
||||
}); |
||||
const unsubscribeId = await resource.subscribeToNotifications(); |
||||
this.activeResourceSubscriptions[resource.uri] = unsubscribeId; |
||||
// Unsubscribe in case unsubscribe call came in mid subscription
|
||||
if (!this.curOnDataChanged) { |
||||
await this.unsubscribeFromResource(resource.uri); |
||||
} |
||||
resolve(); |
||||
this.resourcesWithSubscriptionInProgress[resource.uri] = |
||||
undefined; |
||||
}, |
||||
} |
||||
: {}; |
||||
await exploreLinks( |
||||
this.parentDataset, |
||||
this.shapeType, |
||||
this.startingResource, |
||||
this.startingSubject, |
||||
this.linkQueryInput, |
||||
exploreOptions, |
||||
); |
||||
// Clean up unused subscriptions
|
||||
await Promise.all( |
||||
Array.from(resourcesToUnsubscribeFrom).map(async (uri) => |
||||
this.unsubscribeFromResource(uri), |
||||
), |
||||
); |
||||
}; |
||||
await this.curOnDataChanged({}, "BEGIN_SUB", [null, null, null, null]); |
||||
return subscriptionId; |
||||
} |
||||
|
||||
private async unsubscribeFromResource(uri) { |
||||
const resource = this.parentDataset.getResource(uri); |
||||
const unsubscribeId = this.activeResourceSubscriptions[uri]; |
||||
delete this.activeResourceSubscriptions[uri]; |
||||
await resource.unsubscribeFromNotifications(unsubscribeId); |
||||
} |
||||
|
||||
private async fullUnsubscribe(): Promise<void> { |
||||
if (this.curOnDataChanged) { |
||||
this.parentDataset.removeListenerFromAllEvents(this.curOnDataChanged); |
||||
this.curOnDataChanged = undefined; |
||||
} |
||||
await Promise.all( |
||||
Object.keys(this.activeResourceSubscriptions).map(async (uri) => { |
||||
this.unsubscribeFromResource(uri); |
||||
}), |
||||
); |
||||
} |
||||
|
||||
async unsubscribe(unsubscribeId: string): Promise<void> { |
||||
this.thisUnsubscribeIds.delete(unsubscribeId); |
||||
if (this.thisUnsubscribeIds.size === 0) { |
||||
await this.fullUnsubscribe(); |
||||
} |
||||
} |
||||
|
||||
async unsubscribeAll() { |
||||
this.thisUnsubscribeIds.clear(); |
||||
await this.fullUnsubscribe(); |
||||
} |
||||
|
||||
fromSubject(): ExpandDeep<LQReturn<Type, QueryInput>> { |
||||
return this.ldoBuilder.fromSubject( |
||||
this.startingSubject, |
||||
) as unknown as ExpandDeep<LQReturn<Type, QueryInput>>; |
||||
} |
||||
|
||||
getSubscribedResources(): Plugins[number]["types"]["resource"][] { |
||||
return Object.keys(this.activeResourceSubscriptions).map((uri) => |
||||
this.parentDataset.getResource(uri), |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,162 @@ |
||||
import type { LdoBase, ShapeType } from "@ldo/ldo"; |
||||
import type { ConnectedPlugin } from "../types/ConnectedPlugin"; |
||||
import type { SubjectNode } from "@ldo/rdf-utils"; |
||||
import type { LQInput } from "../types/ILinkQuery"; |
||||
import { BasicLdSet } from "@ldo/jsonld-dataset-proxy"; |
||||
import type { IConnectedLdoDataset } from "../types/IConnectedLdoDataset"; |
||||
import { createTrackingProxyBuilder } from "../trackingProxy/createTrackingProxy"; |
||||
import type { nodeEventListener } from "@ldo/subscribable-dataset"; |
||||
import type { Quad } from "@rdfjs/types"; |
||||
|
||||
/** |
||||
* @internal |
||||
*/ |
||||
interface ExploreLinksOptions<Plugins extends ConnectedPlugin[]> { |
||||
onResourceEncountered?: ( |
||||
resource: Plugins[number]["types"]["resource"], |
||||
) => Promise<void>; |
||||
onCoveredDataChanged?: nodeEventListener<Quad>; |
||||
shouldRefreshResources?: boolean; |
||||
} |
||||
|
||||
/** |
||||
* @internal |
||||
*/ |
||||
export async function exploreLinks< |
||||
Type extends LdoBase, |
||||
Plugins extends ConnectedPlugin[], |
||||
>( |
||||
dataset: IConnectedLdoDataset<Plugins>, |
||||
shapeType: ShapeType<Type>, |
||||
startingResource: Plugins[number]["types"]["resource"], |
||||
startingSubject: SubjectNode | string, |
||||
queryInput: LQInput<Type>, |
||||
options?: ExploreLinksOptions<Plugins>, |
||||
): Promise<void> { |
||||
// Do an initial check of the resources.
|
||||
const readResult = options?.shouldRefreshResources |
||||
? await startingResource.read() |
||||
: await startingResource.readIfUnfetched(); |
||||
if (readResult.isError) return; |
||||
|
||||
if (options?.onResourceEncountered) |
||||
await options?.onResourceEncountered(startingResource); |
||||
|
||||
const proxyBuilder = options?.onCoveredDataChanged |
||||
? createTrackingProxyBuilder( |
||||
dataset, |
||||
shapeType, |
||||
options?.onCoveredDataChanged, |
||||
) |
||||
: dataset.usingType(shapeType); |
||||
const ldObject = proxyBuilder.fromSubject(startingSubject); |
||||
|
||||
const encounteredDuringThisExploration = new Set<string>([ |
||||
startingResource.uri, |
||||
]); |
||||
|
||||
// Recursively explore the rest
|
||||
await exploreLinksRecursive( |
||||
dataset, |
||||
ldObject, |
||||
queryInput, |
||||
encounteredDuringThisExploration, |
||||
options, |
||||
); |
||||
} |
||||
|
||||
export async function exploreLinksRecursive< |
||||
Type extends LdoBase, |
||||
Plugins extends ConnectedPlugin[], |
||||
>( |
||||
dataset: IConnectedLdoDataset<Plugins>, |
||||
ldObject: Type, |
||||
queryInput: LQInput<Type>, |
||||
encounteredDuringThisExploration: Set<string>, |
||||
options?: ExploreLinksOptions<Plugins>, |
||||
): Promise<void> { |
||||
const shouldFetch = shouldFetchResource( |
||||
dataset, |
||||
ldObject, |
||||
queryInput, |
||||
encounteredDuringThisExploration, |
||||
); |
||||
const resourceToFetch = dataset.getResource(ldObject["@id"]); |
||||
if (shouldFetch) { |
||||
const readResult = options?.shouldRefreshResources |
||||
? await resourceToFetch.read() |
||||
: await resourceToFetch.readIfUnfetched(); |
||||
// If there was an error with the read, the traversal is done.
|
||||
if (readResult.isError) { |
||||
return; |
||||
} |
||||
} |
||||
if (!encounteredDuringThisExploration.has(resourceToFetch.uri)) { |
||||
encounteredDuringThisExploration.add(resourceToFetch.uri); |
||||
if (options?.onResourceEncountered) |
||||
await options.onResourceEncountered(resourceToFetch); |
||||
} |
||||
// Recurse through the other elemenets
|
||||
await Promise.all( |
||||
Object.entries(queryInput).map(async ([queryKey, queryValue]) => { |
||||
if ( |
||||
queryValue != undefined && |
||||
queryValue !== true && |
||||
ldObject[queryKey] != undefined |
||||
) { |
||||
if (ldObject[queryKey] instanceof BasicLdSet) { |
||||
await Promise.all( |
||||
ldObject[queryKey].map(async (item) => { |
||||
await exploreLinksRecursive( |
||||
dataset, |
||||
item, |
||||
queryValue, |
||||
encounteredDuringThisExploration, |
||||
options, |
||||
); |
||||
}), |
||||
); |
||||
} else { |
||||
await exploreLinksRecursive( |
||||
dataset, |
||||
ldObject[queryKey], |
||||
queryValue, |
||||
encounteredDuringThisExploration, |
||||
options, |
||||
); |
||||
} |
||||
} |
||||
}), |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* Determines if a resource needs to be fetched based on given data |
||||
*/ |
||||
export function shouldFetchResource< |
||||
Type extends LdoBase, |
||||
Plugins extends ConnectedPlugin[], |
||||
>( |
||||
dataset: IConnectedLdoDataset<Plugins>, |
||||
ldObject: Type, |
||||
queryInput: LQInput<Type>, |
||||
encounteredDuringThisExploration: Set<string>, |
||||
): boolean { |
||||
const linkedResourceUri: string | undefined = ldObject["@id"]; |
||||
// If it's a blank node, no need to fetch
|
||||
if (!linkedResourceUri) return false; |
||||
const linkedResource = dataset.getResource(linkedResourceUri); |
||||
// If we've already explored the resource in this exporation, do not fetch
|
||||
if (encounteredDuringThisExploration.has(linkedResource.uri)) return false; |
||||
|
||||
return Object.entries(queryInput).some(([queryKey, queryValue]) => { |
||||
// If value is undefined then no need to fetch
|
||||
if (!queryValue) return false; |
||||
// Always fetch if there's a set in the object
|
||||
if (ldObject[queryKey] instanceof BasicLdSet) return true; |
||||
// Fetch if a singleton set is not present
|
||||
if (ldObject[queryKey] == undefined) return true; |
||||
// Otherwise no need t to fetch
|
||||
return false; |
||||
}); |
||||
} |
@ -0,0 +1,42 @@ |
||||
import { |
||||
ContextUtil, |
||||
JsonldDatasetProxyBuilder, |
||||
} from "@ldo/jsonld-dataset-proxy"; |
||||
import { LdoBuilder } from "@ldo/ldo"; |
||||
import type { LdoBase, LdoDataset, ShapeType } from "@ldo/ldo"; |
||||
import { TrackingProxyContext } from "./TrackingProxyContext"; |
||||
import { defaultGraph } from "@rdfjs/data-model"; |
||||
import type { nodeEventListener } from "@ldo/subscribable-dataset"; |
||||
import type { Quad } from "@rdfjs/types"; |
||||
|
||||
/** |
||||
* @internal |
||||
* Creates a Linked Data Object builder that when creating linked data objects |
||||
* it tracks when something that was read from it is updated and triggers some |
||||
* action based on that. |
||||
*/ |
||||
export function createTrackingProxyBuilder<Type extends LdoBase>( |
||||
dataset: LdoDataset, |
||||
shapeType: ShapeType<Type>, |
||||
onUpdate: nodeEventListener<Quad>, |
||||
): LdoBuilder<Type> { |
||||
// Remove all current subscriptions
|
||||
// dataset.removeListenerFromAllEvents(onUpdate);
|
||||
|
||||
// Rebuild the LdoBuilder from scratch to inject TrackingProxyContext
|
||||
const contextUtil = new ContextUtil(shapeType.context); |
||||
const proxyContext = new TrackingProxyContext( |
||||
{ |
||||
dataset, |
||||
contextUtil, |
||||
writeGraphs: [defaultGraph()], |
||||
languageOrdering: ["none", "en", "other"], |
||||
}, |
||||
onUpdate, |
||||
); |
||||
const builder = new LdoBuilder( |
||||
new JsonldDatasetProxyBuilder(proxyContext), |
||||
shapeType, |
||||
); |
||||
return builder; |
||||
} |
@ -1,7 +1,7 @@ |
||||
/* eslint-disable @typescript-eslint/no-explicit-any */ |
||||
import type { ConnectedContext } from "./ConnectedContext"; |
||||
import type { Resource } from "./Resource"; |
||||
import type { ErrorResult } from "./results/error/ErrorResult"; |
||||
import type { Resource } from "../Resource"; |
||||
import type { ErrorResult } from "../results/error/ErrorResult"; |
||||
|
||||
/** |
||||
* A ConnectedPlugin can be passed to a ConnectedDataset to allow it to connect |
@ -0,0 +1,15 @@ |
||||
import type { LdoBase, LdoBuilder } from "@ldo/ldo"; |
||||
import type { ConnectedPlugin } from "./ConnectedPlugin"; |
||||
import type { SubjectNode } from "@ldo/rdf-utils"; |
||||
import type { ILinkQuery, LQInput } from "./ILinkQuery"; |
||||
|
||||
export interface IConnectedLdoBuilder< |
||||
Type extends LdoBase, |
||||
Plugins extends ConnectedPlugin[], |
||||
> extends LdoBuilder<Type> { |
||||
startLinkQuery<Input extends LQInput<Type>>( |
||||
startingResource: Plugins[number]["types"]["resource"], |
||||
startingSubject: SubjectNode | string, |
||||
linkQueryInput: Input, |
||||
): ILinkQuery<Type, Input>; |
||||
} |
@ -0,0 +1,126 @@ |
||||
// This file is a stripped down version of a full-implmentation of a global
|
||||
// query interface found here https://github.com/o-development/ldo-query/blob/main/lib/ShapeQuery.ts
|
||||
// If I ever want to implement a global query interface, this is a good place
|
||||
// to start.
|
||||
|
||||
import type { LdoBase, LdSet } from "@ldo/ldo"; |
||||
// import { SolidProfileShapeShapeType } from "../../test/.ldo/solidProfile.shapeTypes";
|
||||
// import type { SolidProfileShape } from "../../test/.ldo/solidProfile.typings";
|
||||
|
||||
/** |
||||
* Link Query Input |
||||
*/ |
||||
export type LQInput<Type> = LQInputObject<Type>; |
||||
|
||||
export type LQInputObject<Type> = Partial<{ |
||||
[key in Exclude<keyof Type, "@context">]: LQInputFlattenSet<Type[key]>; |
||||
}>; |
||||
|
||||
export type LQInputSubSet<Type> = Type extends object |
||||
? LQInputObject<Type> |
||||
: true; |
||||
|
||||
export type LQInputFlattenSet<Type> = Type extends LdSet<infer SetSubType> |
||||
? LQInputSubSet<SetSubType> |
||||
: LQInputSubSet<Type>; |
||||
|
||||
/** |
||||
* Link Query Input Default |
||||
*/ |
||||
// TODO: I don't remember why I need this. Delete if unneeded
|
||||
// export type LQInputDefaultType<Type> = {
|
||||
// [key in keyof Type]: Type[key] extends object ? undefined : true;
|
||||
// };
|
||||
|
||||
// export type LQInputDefault<Type> =
|
||||
// LQInputDefaultType<Type> extends LQInput<Type>
|
||||
// ? LQInputDefaultType<Type>
|
||||
// : never;
|
||||
|
||||
/** |
||||
* Link Query Return |
||||
*/ |
||||
export type LQReturn<Type, Input extends LQInput<Type>> = LQReturnObject< |
||||
Type, |
||||
Input |
||||
>; |
||||
|
||||
export type LQReturnObject<Type, Input extends LQInputObject<Type>> = { |
||||
[key in Exclude< |
||||
keyof Required<Type>, |
||||
"@context" |
||||
> as undefined extends Input[key] |
||||
? never |
||||
: key]: Input[key] extends LQInputFlattenSet<Type[key]> |
||||
? undefined extends Type[key] |
||||
? LQReturnExpandSet<Type[key], Input[key]> | undefined |
||||
: LQReturnExpandSet<Type[key], Input[key]> |
||||
: never; |
||||
}; |
||||
|
||||
export type LQReturnSubSet<Type, Input> = Input extends LQInputSubSet<Type> |
||||
? Input extends LQInputObject<Type> |
||||
? Input extends true |
||||
? Type |
||||
: LQReturnObject<Type, Input> |
||||
: Type |
||||
: never; |
||||
|
||||
export type LQReturnExpandSet< |
||||
Type, |
||||
Input extends LQInputFlattenSet<Type>, |
||||
> = NonNullable<Type> extends LdSet<infer SetSubType> |
||||
? LdSet<LQReturnSubSet<SetSubType, Input>> |
||||
: LQReturnSubSet<Type, Input>; |
||||
|
||||
export type ExpandDeep<T> = T extends LdSet<infer U> |
||||
? LdSet<ExpandDeep<U>> // recursively expand sets
|
||||
: T extends object |
||||
? { [K in keyof T]: ExpandDeep<T[K]> } // recursively expand objects
|
||||
: T; // base case (primitive types)
|
||||
|
||||
/** |
||||
* ILinkQuery: Manages resources in a link query |
||||
*/ |
||||
export interface LinkQueryRunOptions { |
||||
reload?: boolean; |
||||
} |
||||
|
||||
export interface ILinkQuery<Type extends LdoBase, Input extends LQInput<Type>> { |
||||
run( |
||||
options?: LinkQueryRunOptions, |
||||
): Promise<ExpandDeep<LQReturn<Type, Input>>>; |
||||
subscribe(): Promise<string>; |
||||
unsubscribe(subscriptionId: string): Promise<void>; |
||||
unsubscribeAll(): Promise<void>; |
||||
fromSubject(): ExpandDeep<LQReturn<Type, Input>>; |
||||
} |
||||
|
||||
// function test<Type extends LdoBase, Input extends LQInput<Type>>(
|
||||
// shapeType: ShapeType<Type>,
|
||||
// input: Input,
|
||||
// ): ExpandDeep<LQReturn<Type, Input>> {
|
||||
// throw new Error("Not Implemented");
|
||||
// }
|
||||
|
||||
// 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,
|
||||
// },
|
||||
// });
|
@ -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,58 @@ |
||||
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 THIRD_PROFILE_URI = `${BASE_CONTAINER}thirdProfile.ttl`; |
||||
export const THIRD_PROFILE_SUBJECT = `${THIRD_PROFILE_URI}#me`; |
||||
|
||||
export const linkTraversalData: ResourceInfo = { |
||||
slug: "test-container/", |
||||
isContainer: true, |
||||
contains: [ |
||||
{ |
||||
slug: "mainProfile.ttl", |
||||
isContainer: false, |
||||
mimeType: "text/turtle", |
||||
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/turtle", |
||||
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> . |
||||
`,
|
||||
}, |
||||
{ |
||||
slug: "thirdProfile.ttl", |
||||
isContainer: false, |
||||
mimeType: "text/turtle", |
||||
data: ` |
||||
@prefix foaf: <http://xmlns.com/foaf/0.1/> . |
||||
@prefix : <#> . |
||||
|
||||
:me a foaf:Person ; |
||||
foaf:name "Third User" ; |
||||
foaf:mbox <mailto:third@example.org> ; |
||||
foaf:knows <http://localhost:3005/test-container/mainProfile.ttl#me> . |
||||
`,
|
||||
}, |
||||
], |
||||
}; |
@ -0,0 +1,216 @@ |
||||
import type { ConnectedLdoDataset } from "../src/ConnectedLdoDataset"; |
||||
import { changeData, commitData, createConnectedLdoDataset } from "../src"; |
||||
import { |
||||
solidConnectedPlugin, |
||||
type SolidConnectedPlugin, |
||||
} from "@ldo/connected-solid"; |
||||
import { setupServer } from "@ldo/test-solid-server"; |
||||
import { |
||||
linkTraversalData, |
||||
MAIN_PROFILE_SUBJECT, |
||||
MAIN_PROFILE_URI, |
||||
OTHER_PROFILE_URI, |
||||
THIRD_PROFILE_SUBJECT, |
||||
THIRD_PROFILE_URI, |
||||
} from "./LinkTraversalData"; |
||||
import { SolidProfileShapeShapeType } from "./.ldo/solidProfile.shapeTypes"; |
||||
import { wait } from "./util/wait"; |
||||
|
||||
describe("Link Traversal", () => { |
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
let solidLdoDataset: ConnectedLdoDataset<SolidConnectedPlugin[]>; |
||||
|
||||
const s = setupServer(3005, linkTraversalData); |
||||
|
||||
beforeEach(async () => { |
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
solidLdoDataset = createConnectedLdoDataset([solidConnectedPlugin]); |
||||
solidLdoDataset.setContext("solid", { fetch: s.fetchMock }); |
||||
}); |
||||
|
||||
it("does a simple run to traverse data", async () => { |
||||
const mainProfileResource = solidLdoDataset.getResource(MAIN_PROFILE_URI); |
||||
const data = await solidLdoDataset |
||||
.usingType(SolidProfileShapeShapeType) |
||||
.startLinkQuery(mainProfileResource, MAIN_PROFILE_SUBJECT, { |
||||
name: true, |
||||
knows: { |
||||
name: true, |
||||
}, |
||||
}) |
||||
.run(); |
||||
const resourceUris = solidLdoDataset |
||||
.getResources() |
||||
.map((resource) => resource.uri); |
||||
expect(resourceUris.length).toBe(3); |
||||
expect(resourceUris).toContain(MAIN_PROFILE_URI); |
||||
expect(resourceUris).toContain(OTHER_PROFILE_URI); |
||||
expect(data.name).toBe("Main User"); |
||||
expect(data.knows?.toArray()[0].name).toBe("Other User"); |
||||
}); |
||||
|
||||
it("handles subscriptions if data changes locally", async () => { |
||||
const mainProfileResource = solidLdoDataset.getResource(MAIN_PROFILE_URI); |
||||
const linkQuery = solidLdoDataset |
||||
.usingType(SolidProfileShapeShapeType) |
||||
.startLinkQuery(mainProfileResource, MAIN_PROFILE_SUBJECT, { |
||||
name: true, |
||||
knows: { |
||||
name: true, |
||||
}, |
||||
}); |
||||
await linkQuery.subscribe(); |
||||
|
||||
// Should have regular information
|
||||
let mainProfile = solidLdoDataset |
||||
.usingType(SolidProfileShapeShapeType) |
||||
.fromSubject(MAIN_PROFILE_SUBJECT); |
||||
let resourceUris = solidLdoDataset |
||||
.getResources() |
||||
.map((resource) => resource.uri); |
||||
expect(resourceUris.length).toBe(3); |
||||
expect(resourceUris).toContain(MAIN_PROFILE_URI); |
||||
expect(resourceUris).toContain(OTHER_PROFILE_URI); |
||||
expect(mainProfile.name).toBe("Main User"); |
||||
expect(mainProfile.knows?.size).toBe(1); |
||||
expect(mainProfile.knows?.toArray()[0].name).toBe("Other User"); |
||||
|
||||
// Update to include a new document
|
||||
const cMainProfile = changeData(mainProfile, mainProfileResource); |
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
cMainProfile.knows?.add({ "@id": THIRD_PROFILE_SUBJECT }); |
||||
await commitData(cMainProfile); |
||||
|
||||
// Wait for 200ms to allow the other file to be fetched
|
||||
await wait(200); |
||||
|
||||
// After the data is committed, the third profile should be present
|
||||
mainProfile = solidLdoDataset |
||||
.usingType(SolidProfileShapeShapeType) |
||||
.fromSubject(MAIN_PROFILE_SUBJECT); |
||||
resourceUris = solidLdoDataset |
||||
.getResources() |
||||
.map((resource) => resource.uri); |
||||
expect(resourceUris.length).toBe(4); |
||||
expect(resourceUris).toContain(MAIN_PROFILE_URI); |
||||
expect(resourceUris).toContain(OTHER_PROFILE_URI); |
||||
expect(resourceUris).toContain(THIRD_PROFILE_URI); |
||||
expect(mainProfile.name).toBe("Main User"); |
||||
expect(mainProfile.knows?.size).toBe(2); |
||||
const knowNames = mainProfile.knows?.map((knowsPerson) => knowsPerson.name); |
||||
expect(knowNames).toContain("Other User"); |
||||
expect(knowNames).toContain("Third User"); |
||||
|
||||
// Unsubscribe
|
||||
}); |
||||
|
||||
it.only("handles subscriptions if data changes on the Pod", async () => { |
||||
const mainProfileResource = solidLdoDataset.getResource(MAIN_PROFILE_URI); |
||||
const linkQuery = solidLdoDataset |
||||
.usingType(SolidProfileShapeShapeType) |
||||
.startLinkQuery(mainProfileResource, MAIN_PROFILE_SUBJECT, { |
||||
name: true, |
||||
knows: { |
||||
name: true, |
||||
}, |
||||
}); |
||||
|
||||
const unsubscribeId = await linkQuery.subscribe(); |
||||
|
||||
// Should have regular information
|
||||
let mainProfile = solidLdoDataset |
||||
.usingType(SolidProfileShapeShapeType) |
||||
.fromSubject(MAIN_PROFILE_SUBJECT); |
||||
let resourceUris = solidLdoDataset |
||||
.getResources() |
||||
.map((resource) => resource.uri); |
||||
expect(resourceUris.length).toBe(3); |
||||
expect(resourceUris).toContain(MAIN_PROFILE_URI); |
||||
expect(resourceUris).toContain(OTHER_PROFILE_URI); |
||||
expect(mainProfile.name).toBe("Main User"); |
||||
expect(mainProfile.knows?.size).toBe(1); |
||||
expect(mainProfile.knows?.toArray()[0].name).toBe("Other User"); |
||||
|
||||
let subscribedResources = linkQuery |
||||
.getSubscribedResources() |
||||
.map((resource) => resource.uri); |
||||
expect(subscribedResources.length).toBe(2); |
||||
expect(subscribedResources).toContain(MAIN_PROFILE_URI); |
||||
expect(subscribedResources).toContain(OTHER_PROFILE_URI); |
||||
|
||||
// Update data on the Pod
|
||||
await s.authFetch(MAIN_PROFILE_URI, { |
||||
method: "PATCH", |
||||
body: "INSERT DATA { <http://localhost:3005/test-container/mainProfile.ttl#me> <http://xmlns.com/foaf/0.1/knows> <http://localhost:3005/test-container/thirdProfile.ttl#me> . }", |
||||
headers: { |
||||
"Content-Type": "application/sparql-update", |
||||
}, |
||||
}); |
||||
await wait(1000); |
||||
|
||||
// After the data is committed, the third profile should be present
|
||||
mainProfile = solidLdoDataset |
||||
.usingType(SolidProfileShapeShapeType) |
||||
.fromSubject(MAIN_PROFILE_SUBJECT); |
||||
resourceUris = solidLdoDataset |
||||
.getResources() |
||||
.map((resource) => resource.uri); |
||||
expect(resourceUris.length).toBe(4); |
||||
expect(resourceUris).toContain(MAIN_PROFILE_URI); |
||||
expect(resourceUris).toContain(OTHER_PROFILE_URI); |
||||
expect(resourceUris).toContain(THIRD_PROFILE_URI); |
||||
expect(mainProfile.name).toBe("Main User"); |
||||
expect(mainProfile.knows?.size).toBe(2); |
||||
const knowNames = mainProfile.knows?.map((knowsPerson) => knowsPerson.name); |
||||
expect(knowNames).toContain("Other User"); |
||||
expect(knowNames).toContain("Third User"); |
||||
|
||||
subscribedResources = linkQuery |
||||
.getSubscribedResources() |
||||
.map((resource) => resource.uri); |
||||
expect(subscribedResources.length).toBe(3); |
||||
expect(subscribedResources).toContain(MAIN_PROFILE_URI); |
||||
expect(subscribedResources).toContain(OTHER_PROFILE_URI); |
||||
expect(subscribedResources).toContain(THIRD_PROFILE_URI); |
||||
|
||||
// Unsubscribe
|
||||
await linkQuery.unsubscribe(unsubscribeId); |
||||
|
||||
await wait(200); |
||||
|
||||
s.fetchMock.mockClear(); |
||||
|
||||
// Does not update when unsubscribed
|
||||
await s.authFetch(MAIN_PROFILE_URI, { |
||||
method: "PATCH", |
||||
body: "INSERT DATA { <http://localhost:3005/test-container/mainProfile.ttl#me> <http://xmlns.com/foaf/0.1/knows> <http://localhost:3005/test-container/fourthProfile.ttl#me> . }", |
||||
headers: { |
||||
"Content-Type": "application/sparql-update", |
||||
}, |
||||
}); |
||||
await wait(1000); |
||||
|
||||
expect(s.fetchMock).not.toHaveBeenCalled(); |
||||
subscribedResources = linkQuery |
||||
.getSubscribedResources() |
||||
.map((resource) => resource.uri); |
||||
expect(subscribedResources.length).toBe(0); |
||||
|
||||
// Check that all resources are unsubscribed from notifications
|
||||
const resources = solidLdoDataset.getResources(); |
||||
resources.forEach((resource) => { |
||||
expect(resource.isSubscribedToNotifications()).toBe(false); |
||||
}); |
||||
|
||||
const cMainProfile = changeData(mainProfile, mainProfileResource); |
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
cMainProfile.knows?.add({ |
||||
"@id": "http://localhost:3005/test-container/fifthProfile.ttl#me", |
||||
}); |
||||
await commitData(cMainProfile); |
||||
}); |
||||
}); |
@ -1,73 +0,0 @@ |
||||
/* eslint-disable @typescript-eslint/no-explicit-any */ |
||||
import EventEmitter from "events"; |
||||
import type { ResourceError } from "../src"; |
||||
import { |
||||
Unfetched, |
||||
type ConnectedResult, |
||||
type Resource, |
||||
type ResourceEventEmitter, |
||||
} from "../src"; |
||||
import type { DatasetChanges } from "@ldo/rdf-utils"; |
||||
import type { ReadSuccess } from "../src/results/success/ReadSuccess"; |
||||
import type { UpdateSuccess } from "../src/results/success/UpdateSuccess"; |
||||
|
||||
export class MockResouce |
||||
extends (EventEmitter as new () => ResourceEventEmitter) |
||||
implements Resource |
||||
{ |
||||
isError = false as const; |
||||
uri: string; |
||||
type = "mock" as const; |
||||
status: ConnectedResult; |
||||
|
||||
constructor(uri: string) { |
||||
super(); |
||||
this.uri = uri; |
||||
this.status = new Unfetched(this); |
||||
} |
||||
|
||||
isLoading(): boolean { |
||||
throw new Error("Method not implemented."); |
||||
} |
||||
isFetched(): boolean { |
||||
throw new Error("Method not implemented."); |
||||
} |
||||
isUnfetched(): boolean { |
||||
throw new Error("Method not implemented."); |
||||
} |
||||
isDoingInitialFetch(): boolean { |
||||
throw new Error("Method not implemented."); |
||||
} |
||||
isPresent(): boolean | undefined { |
||||
throw new Error("Method not implemented."); |
||||
} |
||||
isAbsent(): boolean | undefined { |
||||
throw new Error("Method not implemented."); |
||||
} |
||||
isSubscribedToNotifications(): boolean { |
||||
throw new Error("Method not implemented."); |
||||
} |
||||
read(): Promise<ReadSuccess<any> | ResourceError<any>> { |
||||
throw new Error("Method not implemented."); |
||||
} |
||||
readIfUnfetched(): Promise<ReadSuccess<any> | ResourceError<any>> { |
||||
throw new Error("Method not implemented."); |
||||
} |
||||
update( |
||||
_datasetChanges: DatasetChanges, |
||||
): Promise<UpdateSuccess<any> | ResourceError<any>> { |
||||
throw new Error("Method not implemented."); |
||||
} |
||||
subscribeToNotifications(_callbacks?: { |
||||
onNotification: (message: any) => void; |
||||
onNotificationError: (err: Error) => void; |
||||
}): Promise<string> { |
||||
throw new Error("Method not implemented."); |
||||
} |
||||
unsubscribeFromNotifications(_subscriptionId: string): Promise<void> { |
||||
throw new Error("Method not implemented."); |
||||
} |
||||
unsubscribeFromAllNotifications(): Promise<void> { |
||||
throw new Error("Method not implemented."); |
||||
} |
||||
} |
@ -0,0 +1,59 @@ |
||||
/* eslint-disable @typescript-eslint/no-explicit-any */ |
||||
import EventEmitter from "events"; |
||||
import type { ResourceError } from "../../src"; |
||||
import { |
||||
Unfetched, |
||||
type ConnectedResult, |
||||
type Resource, |
||||
type ResourceEventEmitter, |
||||
} from "../../src"; |
||||
import type { DatasetChanges } from "@ldo/rdf-utils"; |
||||
import type { ReadSuccess } from "../../src/results/success/ReadSuccess"; |
||||
import type { UpdateSuccess } from "../../src/results/success/UpdateSuccess"; |
||||
|
||||
export class MockResource |
||||
extends (EventEmitter as new () => ResourceEventEmitter) |
||||
implements Resource |
||||
{ |
||||
isError = false as const; |
||||
uri: string; |
||||
type = "mock" as const; |
||||
status: ConnectedResult; |
||||
|
||||
constructor(uri: string) { |
||||
super(); |
||||
this.uri = uri; |
||||
this.status = new Unfetched(this); |
||||
} |
||||
|
||||
isLoading = jest.fn<boolean, []>(); |
||||
isFetched = jest.fn<boolean, []>(); |
||||
isUnfetched = jest.fn<boolean, []>(); |
||||
isDoingInitialFetch = jest.fn<boolean, []>(); |
||||
isPresent = jest.fn<boolean | undefined, []>(); |
||||
isAbsent = jest.fn<boolean | undefined, []>(); |
||||
isSubscribedToNotifications = jest.fn<boolean, []>(); |
||||
|
||||
read = jest.fn<Promise<ReadSuccess<any> | ResourceError<any>>, []>(); |
||||
readIfUnfetched = jest.fn< |
||||
Promise<ReadSuccess<any> | ResourceError<any>>, |
||||
[] |
||||
>(); |
||||
update = jest.fn< |
||||
Promise<UpdateSuccess<any> | ResourceError<any>>, |
||||
[DatasetChanges] |
||||
>(); |
||||
|
||||
subscribeToNotifications = jest.fn< |
||||
Promise<string>, |
||||
[ |
||||
{ |
||||
onNotification: (message: any) => void; |
||||
onNotificationError: (err: Error) => void; |
||||
}?, |
||||
] |
||||
>(); |
||||
|
||||
unsubscribeFromNotifications = jest.fn<Promise<void>, [string]>(); |
||||
unsubscribeFromAllNotifications = jest.fn<Promise<void>, []>(); |
||||
} |
@ -0,0 +1,3 @@ |
||||
export async function wait(time: number) { |
||||
return new Promise((resolve) => setTimeout(resolve, time)); |
||||
} |
@ -0,0 +1,72 @@ |
||||
import type { |
||||
ConnectedLdoDataset, |
||||
ConnectedPlugin, |
||||
ExpandDeep, |
||||
LQInput, |
||||
LQReturn, |
||||
ResourceLinkQuery, |
||||
} from "@ldo/connected"; |
||||
import type { LdoBase, LdoBuilder, ShapeType } from "@ldo/ldo"; |
||||
import type { SubjectNode } from "@ldo/rdf-utils"; |
||||
import { useCallback, useEffect, useRef, useState } from "react"; |
||||
import { useTrackingProxy } from "../util/useTrackingProxy"; |
||||
|
||||
/** |
||||
* @internal |
||||
* |
||||
* Creates a useMatchSubject function. |
||||
*/ |
||||
export function createUseLinkQuery<Plugins extends ConnectedPlugin[]>( |
||||
dataset: ConnectedLdoDataset<Plugins>, |
||||
) { |
||||
/** |
||||
* Returns an array of matching linked data objects. Triggers a rerender if |
||||
* the data is updated. |
||||
*/ |
||||
return function useQueryLink< |
||||
Type extends LdoBase, |
||||
QueryInput extends LQInput<Type>, |
||||
>( |
||||
shapeType: ShapeType<Type>, |
||||
startingResource: string, |
||||
startingSubject: SubjectNode | string, |
||||
linkQuery: QueryInput, |
||||
): ExpandDeep<LQReturn<Type, QueryInput>> | undefined { |
||||
const linkQueryRef = useRef< |
||||
ResourceLinkQuery<Type, QueryInput, Plugins> | undefined |
||||
>(); |
||||
|
||||
const [isLoading, setIsLoading] = useState(true); |
||||
|
||||
useEffect(() => { |
||||
if (linkQueryRef.current) { |
||||
linkQueryRef.current.unsubscribeAll(); |
||||
} |
||||
const resource = dataset.getResource(startingResource); |
||||
setIsLoading(true); |
||||
linkQueryRef.current = dataset |
||||
.usingType(shapeType) |
||||
.startLinkQuery(resource, startingSubject, linkQuery); |
||||
|
||||
linkQueryRef.current.subscribe().then(() => setIsLoading(false)); |
||||
|
||||
return () => { |
||||
linkQueryRef.current?.unsubscribeAll(); |
||||
}; |
||||
}, [shapeType, startingResource, startingSubject, linkQuery]); |
||||
|
||||
const fromSubject = useCallback( |
||||
(builder: LdoBuilder<Type>) => { |
||||
if (!startingSubject) return; |
||||
return builder.fromSubject(startingSubject); |
||||
}, |
||||
[startingSubject], |
||||
); |
||||
|
||||
const linkedDataObject = useTrackingProxy(shapeType, fromSubject, dataset); |
||||
|
||||
return isLoading |
||||
? undefined |
||||
: (linkedDataObject as unknown as ExpandDeep<LQReturn<Type, QueryInput>>); |
||||
}; |
||||
} |
@ -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,7 @@ |
||||
@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:3002/example/link-query/other-profile.ttl#me> . |
@ -0,0 +1,7 @@ |
||||
@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:3002/example/link-query/main-profile.ttl#me> . |
@ -0,0 +1,7 @@ |
||||
@prefix foaf: <http://xmlns.com/foaf/0.1/> . |
||||
@prefix : <#> . |
||||
|
||||
:me a foaf:Person ; |
||||
foaf:name "Third User" ; |
||||
foaf:mbox <mailto:third@example.org> ; |
||||
foaf:knows <http://localhost:3002/example/link-query/main-profile.ttl#me> . |
@ -0,0 +1,5 @@ |
||||
{ |
||||
"extends": [ |
||||
"../../.eslintrc" |
||||
] |
||||
} |
@ -0,0 +1,2 @@ |
||||
node_modules |
||||
*/data |
@ -0,0 +1,21 @@ |
||||
MIT License |
||||
|
||||
Copyright (c) 2023 Jackson Morgan |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
@ -0,0 +1,17 @@ |
||||
# @ldo/test-solid-server |
||||
|
||||
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", |
||||
``` |
@ -0,0 +1,34 @@ |
||||
{ |
||||
"name": "@ldo/test-solid-server", |
||||
"version": "1.0.0-alpha.9", |
||||
"description": "A solid server to be used in jest tests", |
||||
"main": "dist/index.js", |
||||
"scripts": { |
||||
"build": "tsc --project tsconfig.build.json && npm run copy-configs", |
||||
"prepublishOnly": "npm run build", |
||||
"copy-configs": "cp -r src/configs dist/configs", |
||||
"lint": "eslint src/** --fix --no-error-on-unmatched-pattern" |
||||
}, |
||||
"repository": { |
||||
"type": "git", |
||||
"url": "git+https://github.com/o-development/ldo.git" |
||||
}, |
||||
"author": "Jackson Morgan", |
||||
"license": "MIT", |
||||
"bugs": { |
||||
"url": "https://github.com/o-development/ldo/issues" |
||||
}, |
||||
"homepage": "https://github.com/o-development/ldo/tree/main/packages/solid#readme", |
||||
"dependencies": { |
||||
"@inrupt/solid-client-authn-core": "^2.2.6", |
||||
"@solid/community-server": "^7.1.3", |
||||
"cross-env": "^7.0.3" |
||||
}, |
||||
"files": [ |
||||
"dist", |
||||
"src" |
||||
], |
||||
"publishConfig": { |
||||
"access": "public" |
||||
} |
||||
} |
@ -0,0 +1,44 @@ |
||||
{ |
||||
"@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." |
||||
] |
||||
} |
||||
] |
||||
} |
@ -0,0 +1,3 @@ |
||||
export * from "./createServer"; |
||||
export * from "./setupTestServer"; |
||||
export * from "./resourceUtils"; |
@ -0,0 +1,75 @@ |
||||
export type ResourceInfo = ContainerInfo | LeafInfo; |
||||
|
||||
interface ContainerInfo { |
||||
slug: string; |
||||
isContainer: true; |
||||
shouldNotInit?: boolean; |
||||
contains: (ContainerInfo | LeafInfo)[]; |
||||
} |
||||
|
||||
interface LeafInfo { |
||||
slug: string; |
||||
isContainer: false; |
||||
data: string; |
||||
shouldNotInit?: boolean; |
||||
mimeType: string; |
||||
} |
||||
|
||||
export async function initResources( |
||||
rootUri: string, |
||||
resourceInfo: ResourceInfo, |
||||
authFetch: typeof fetch, |
||||
): Promise<void> { |
||||
if (resourceInfo?.shouldNotInit) return; |
||||
if (resourceInfo.isContainer) { |
||||
await authFetch(rootUri, { |
||||
method: "POST", |
||||
headers: { |
||||
link: '<http://www.w3.org/ns/ldp#Container>; rel="type"', |
||||
slug: resourceInfo.slug, |
||||
}, |
||||
}); |
||||
await Promise.all( |
||||
resourceInfo.contains.map((subResourceInfo) => |
||||
initResources( |
||||
`${rootUri}${resourceInfo.slug}`, |
||||
subResourceInfo, |
||||
authFetch, |
||||
), |
||||
), |
||||
); |
||||
} else { |
||||
await authFetch(`${rootUri}${resourceInfo.slug}`, { |
||||
method: "PUT", |
||||
headers: { |
||||
"content-type": resourceInfo.mimeType, |
||||
}, |
||||
body: resourceInfo.data, |
||||
}); |
||||
} |
||||
} |
||||
|
||||
export async function cleanResources( |
||||
rootUri: string, |
||||
resourceInfo: ResourceInfo, |
||||
authFetch: typeof fetch, |
||||
): Promise<void> { |
||||
if (resourceInfo.isContainer) { |
||||
await Promise.all( |
||||
resourceInfo.contains.map((subResourceInfo) => |
||||
cleanResources( |
||||
`${rootUri}${resourceInfo.slug}`, |
||||
subResourceInfo, |
||||
authFetch, |
||||
), |
||||
), |
||||
); |
||||
await authFetch(`${rootUri}${resourceInfo.slug}`, { |
||||
method: "DELETE", |
||||
}); |
||||
} else { |
||||
await authFetch(`${rootUri}${resourceInfo.slug}`, { |
||||
method: "DELETE", |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,60 @@ |
||||
/* eslint-disable @typescript-eslint/no-explicit-any */ |
||||
import type { App } from "@solid/community-server"; |
||||
import { createApp } from "./createServer"; |
||||
import path from "path"; |
||||
import type { ResourceInfo } from "./resourceUtils"; |
||||
import { cleanResources, initResources } from "./resourceUtils"; |
||||
import { generateAuthFetch } from "./authFetch"; |
||||
import fs from "fs/promises"; |
||||
|
||||
export function setupServer( |
||||
port: number, |
||||
resourceInfo: ResourceInfo, |
||||
customConfigPath?: string, |
||||
) { |
||||
const data: { |
||||
app: App; |
||||
fetchMock: jest.Mock< |
||||
Promise<Response>, |
||||
[input: RequestInfo | URL, init?: RequestInit | undefined] |
||||
>; |
||||
authFetch: typeof fetch; |
||||
rootUri: string; |
||||
} = { |
||||
rootUri: `http://localhost:${port}/`, |
||||
} as any; |
||||
|
||||
let previousJestId: string | undefined; |
||||
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
|
||||
data.app = await createApp(port, customConfigPath); |
||||
await data.app.start(); |
||||
data.authFetch = await generateAuthFetch(port); |
||||
}); |
||||
|
||||
afterAll(async () => { |
||||
data.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 () => { |
||||
data.fetchMock = jest.fn(data.authFetch); |
||||
// Create a new document called sample.ttl
|
||||
await initResources(data.rootUri, resourceInfo, data.authFetch); |
||||
}); |
||||
|
||||
afterEach(async () => { |
||||
await cleanResources(data.rootUri, resourceInfo, data.authFetch); |
||||
}); |
||||
|
||||
return data; |
||||
} |
@ -0,0 +1,13 @@ |
||||
{ |
||||
"extends": "../../tsconfig.base.json", |
||||
"compilerOptions": { |
||||
"outDir": "./dist" |
||||
}, |
||||
"include": [ |
||||
"./src" |
||||
], |
||||
"exclude": [ |
||||
"./dist", |
||||
"./coverage" |
||||
] |
||||
} |
Loading…
Reference in new issue