parent
d9e4f2c416
commit
d896f50c75
@ -0,0 +1,3 @@ |
|||||||
|
{ |
||||||
|
"extends": ["../../.eslintrc"] |
||||||
|
} |
@ -0,0 +1,2 @@ |
|||||||
|
test/data |
||||||
|
node_modules |
@ -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,238 @@ |
|||||||
|
# @ldo/solid |
||||||
|
|
||||||
|
@ldo/solid is a client that implements the Solid specification with the use of Linked Data Objects. |
||||||
|
|
||||||
|
## Installation |
||||||
|
|
||||||
|
Navigate into your project's root folder and run the following command: |
||||||
|
``` |
||||||
|
cd my_project/ |
||||||
|
npx run @ldo/cli init |
||||||
|
``` |
||||||
|
|
||||||
|
Now install the @ldo/solid library |
||||||
|
|
||||||
|
``` |
||||||
|
npm i @ldo/solid |
||||||
|
``` |
||||||
|
|
||||||
|
<details> |
||||||
|
<summary> |
||||||
|
Manual Installation |
||||||
|
</summary> |
||||||
|
|
||||||
|
If you already have generated ShapeTypes, you may install the `@ldo/ldo` and `@ldo/solid` libraries independently. |
||||||
|
|
||||||
|
``` |
||||||
|
npm i @ldo/ldo @ldo/solid |
||||||
|
``` |
||||||
|
</details> |
||||||
|
|
||||||
|
## Simple Examples |
||||||
|
|
||||||
|
Below is a simple example of @ldo/solid. Assume that a ShapeType was previously generated and placed at `./.ldo/foafProfile.shapeTypes`. Also assume we have a shape type for social media at `./.ldo/socialMediaPost.shapeTypes` |
||||||
|
|
||||||
|
```typescript |
||||||
|
import { changeData, commitData, createSolidLdoDataset } from "@ldo/solid"; |
||||||
|
import { fetch, getDefaultSession } from "@inrupt/solid-client-authn-browser"; |
||||||
|
import { FoafProfileShapeType } from "./.ldo/foafProfile.shapeTypes"; |
||||||
|
import { SocialMediaPostShapeType } from "./.ldo/socialMediaPost.shapeTypes"; |
||||||
|
|
||||||
|
async function main() { |
||||||
|
/** |
||||||
|
* =========================================================================== |
||||||
|
* READING DATA FROM A POD |
||||||
|
* =========================================================================== |
||||||
|
*/ |
||||||
|
|
||||||
|
// Before we begin using @ldo/solid. Let's get the WebId of the current user |
||||||
|
const webIdUri = getDefaultSession().info.webId; |
||||||
|
if (!webIdUri) throw new Error("User is not logged in"); |
||||||
|
|
||||||
|
// Now let's proceed with @ldo/solid. Our first step is setting up a |
||||||
|
// SolidLdoDataset. You can think of this dataset as a local store for all the |
||||||
|
// information in the Solidverse. Don't forget to pass the authenticated fetch |
||||||
|
// function to do your queries! |
||||||
|
const solidLdoDataset = createSolidLdoDataset({ fetch }); |
||||||
|
|
||||||
|
// We'll start with getting a representation of our WebId's resource |
||||||
|
const webIdResource = solidLdoDataset.getResource(webIdUri); |
||||||
|
|
||||||
|
// This resource is currently unfetched |
||||||
|
console.log(webIdResource.isUnfetched()); // Logs true |
||||||
|
|
||||||
|
// So let's fetch it! Running the `read` command will make a request to get |
||||||
|
// the WebId. |
||||||
|
const readResult = await webIdResource.read(); |
||||||
|
|
||||||
|
// @ldo/solid will never throw an error. Instead, it will return errors. This |
||||||
|
// design decision was made to force you to handle any errors. It may seem a |
||||||
|
// bit annoying at first, but it will result in more resiliant code. You can |
||||||
|
// easily follow intellisense tooltips to see what kinds of errors each action |
||||||
|
// can throw. |
||||||
|
if (readResult.isError) { |
||||||
|
switch (readResult.type) { |
||||||
|
case "serverError": |
||||||
|
console.error("The solid server had an error:", readResult.message); |
||||||
|
return; |
||||||
|
case "noncompliantPodError": |
||||||
|
console.error("The Pod responded in a way not compliant with the spec"); |
||||||
|
return; |
||||||
|
default: |
||||||
|
console.error("Some other error was detected:", readResult.message); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// When fetching a data resource, read triples will automatically be added to |
||||||
|
// the solidLdoDataset. You can access them using Linked Data Objects. In |
||||||
|
// the following example we're using a Profile Linked Data Object that was |
||||||
|
// generated with the init step. |
||||||
|
const profile = solidLdoDataset |
||||||
|
.usingType(FoafProfileShapeType) |
||||||
|
.fromSubject(webIdUri); |
||||||
|
|
||||||
|
// Now you can read "profile" like any JSON. |
||||||
|
console.log(profile.name); |
||||||
|
|
||||||
|
/** |
||||||
|
* =========================================================================== |
||||||
|
* MODIFYING DATA |
||||||
|
* =========================================================================== |
||||||
|
*/ |
||||||
|
|
||||||
|
// When we want to modify data the first step is to use the `changeData` |
||||||
|
// function. We pass in an object that we want to change (in this case, |
||||||
|
// "profile") as well an a list of any resources to which we want those |
||||||
|
// changes to be applied (in this case, just the webIdResource). This gives |
||||||
|
// us a new variable (conventionally named with a c for "changed") that we can |
||||||
|
// write changes to. |
||||||
|
const cProfile = changeData(profile, webIdResource); |
||||||
|
|
||||||
|
// We can make changes just like it's regular JSON |
||||||
|
cProfile.name = "Captain Cool Dude"; |
||||||
|
|
||||||
|
// Committing data is as easy as running the "commitData" function. |
||||||
|
const commitResult = await commitData(cProfile); |
||||||
|
|
||||||
|
// Remember to check for and handle errors! We'll keep it short this time. |
||||||
|
if (commitResult.isError) throw commitResult; |
||||||
|
|
||||||
|
/** |
||||||
|
* =========================================================================== |
||||||
|
* CREATING NEW RESOURCES |
||||||
|
* =========================================================================== |
||||||
|
*/ |
||||||
|
|
||||||
|
// Let's create some social media posts to be stored on the Solid Pod! |
||||||
|
// Our first step is going to be finding where to place these posts. In the |
||||||
|
// future, there will be advanced ways to determine the location of resources |
||||||
|
// but for now, let's throw it in the root folder. |
||||||
|
|
||||||
|
// But, first, let's find out where the root folder is. We can take our WebId |
||||||
|
// resource and call `getRootContainer`. Let's assume the root container has |
||||||
|
// a URI "https://example.com/" |
||||||
|
const rootContainer = await webIdResource.getRootContainer(); |
||||||
|
if (rootContainer.isError) throw rootContainer; |
||||||
|
|
||||||
|
// Now, let's create a container for our posts |
||||||
|
const createPostContainerResult = |
||||||
|
await rootContainer.createChildIfAbsent("social-posts/"); |
||||||
|
if (createPostContainerResult.isError) throw createPostContainerResult; |
||||||
|
|
||||||
|
// Most results store the affected resource in the "resource" field. This |
||||||
|
// container has the URI "https://example.com/social-posts/" |
||||||
|
const postContainer = createPostContainerResult.resource; |
||||||
|
|
||||||
|
// Now that we have our container, let's make a Post resource! This is a data |
||||||
|
// resource, which means we can put raw Solid Data (RDF) into it. |
||||||
|
const postResourceResult = |
||||||
|
await postContainer.createChildAndOverwrite("post1.ttl"); |
||||||
|
if (postResourceResult.isError) throw postResourceResult; |
||||||
|
const postResource = postResourceResult.resource; |
||||||
|
|
||||||
|
// We can also create binary resources with things like images |
||||||
|
const imageResourceResult = await postContainer.uploadChildAndOverwrite( |
||||||
|
// name of the binary |
||||||
|
"image1.svg", |
||||||
|
// A blob for the binary |
||||||
|
new Blob([`<svg><circle r="9" /></svg>`]), |
||||||
|
// mime type of the binary |
||||||
|
"image/svg+xml", |
||||||
|
); |
||||||
|
if (imageResourceResult.isError) throw imageResourceResult; |
||||||
|
const imageResource = imageResourceResult.resource; |
||||||
|
|
||||||
|
/** |
||||||
|
* =========================================================================== |
||||||
|
* CREATING NEW DATA |
||||||
|
* =========================================================================== |
||||||
|
*/ |
||||||
|
|
||||||
|
// We create data in a similar way to the way we modify data. We can use the |
||||||
|
// "createData" method. |
||||||
|
const cPost = solidLdoDataset.createData( |
||||||
|
// An LDO ShapeType saying that this is a social media psot |
||||||
|
SocialMediaPostShapeType, |
||||||
|
// The URI of the post (in this case we'll make it the same as the resource) |
||||||
|
postResource.uri, |
||||||
|
// The resource we should write it to |
||||||
|
postResource, |
||||||
|
); |
||||||
|
|
||||||
|
// We can add new data |
||||||
|
cPost.text = "Check out this bad svg:"; |
||||||
|
cPost.image = { "@id": imageResource.uri }; |
||||||
|
|
||||||
|
// And now we commit data |
||||||
|
const newDataResult = await commitData(cPost); |
||||||
|
if (newDataResult.isError) throw newDataResult; |
||||||
|
|
||||||
|
/** |
||||||
|
* =========================================================================== |
||||||
|
* DELETING RESOURCES |
||||||
|
* =========================================================================== |
||||||
|
*/ |
||||||
|
|
||||||
|
// Deleting resources can be done with a single method call. In this case, |
||||||
|
// the container will be deleted along with all its contained resources |
||||||
|
const deleteResult = await postContainer.delete(); |
||||||
|
if (deleteResult.isError) throw deleteResult; |
||||||
|
} |
||||||
|
main(); |
||||||
|
``` |
||||||
|
|
||||||
|
## API Details |
||||||
|
|
||||||
|
SolidLdoDataset |
||||||
|
|
||||||
|
- [createSolidLdoDataset](https://ldo.js.org/latest/api/solid/functions/createSolidLdoDataset/) |
||||||
|
- [SolidLdoDataset](https://ldo.js.org/latest/api/solid/classes/SolidLdoDataset/) |
||||||
|
|
||||||
|
Resources (Manage batching requests) |
||||||
|
|
||||||
|
- [LeafUri](https://ldo.js.org/latest/api/solid/types/LeafUri/) |
||||||
|
- [ContainerUri](https://ldo.js.org/latest/api/solid/types/ContainerUri/) |
||||||
|
- [Leaf](https://ldo.js.org/latest/api/solid/classes/Leaf/) |
||||||
|
- [Container](https://ldo.js.org/latest/api/solid/classes/Container/) |
||||||
|
|
||||||
|
Standalone Functions |
||||||
|
|
||||||
|
- [checkRootContainter](https://ldo.js.org/latest/api/solid/functions/checkRootContainer/) |
||||||
|
- [createDataResource](https://ldo.js.org/latest/api/solid/functions/createDataResource/) |
||||||
|
- [deleteResource](https://ldo.js.org/latest/api/solid/functions/deleteResource/) |
||||||
|
- [readResource](https://ldo.js.org/latest/api/solid/functions/readResource/) |
||||||
|
- [updateResource](https://ldo.js.org/latest/api/solid/functions/updateResource/) |
||||||
|
- [uploadResource](https://ldo.js.org/latest/api/solid/functions/uploadResource/) |
||||||
|
|
||||||
|
Data Functions |
||||||
|
- [changeData](https://ldo.js.org/latest/api/solid/functions/changeData/) |
||||||
|
- [commitData](https://ldo.js.org/latest/api/solid/functions/commitData/) |
||||||
|
|
||||||
|
## Sponsorship |
||||||
|
This project was made possible by a grant from NGI Zero Entrust via nlnet. Learn more on the [NLnet project page](https://nlnet.nl/project/SolidUsableApps/). |
||||||
|
|
||||||
|
[<img src="https://nlnet.nl/logo/banner.png" alt="nlnet foundation logo" width="300" />](https://nlnet.nl/) |
||||||
|
[<img src="https://nlnet.nl/image/logos/NGI0Entrust_tag.svg" alt="NGI Zero Entrust Logo" width="300" />](https://nlnet.nl/) |
||||||
|
|
||||||
|
## Liscense |
||||||
|
MIT |
@ -0,0 +1 @@ |
|||||||
|
module.exports = { presets: ["@babel/preset-env"] }; |
@ -0,0 +1,11 @@ |
|||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const sharedConfig = require("../../jest.config.js"); |
||||||
|
module.exports = { |
||||||
|
...sharedConfig, |
||||||
|
rootDir: "./", |
||||||
|
setupFiles: ["<rootDir>/test/setup-tests.ts"], |
||||||
|
transform: { |
||||||
|
"^.+\\.(ts|tsx)?$": "ts-jest", |
||||||
|
"^.+\\.(js|jsx)$": "babel-jest", |
||||||
|
}, |
||||||
|
}; |
@ -0,0 +1,58 @@ |
|||||||
|
{ |
||||||
|
"name": "@ldo/connected-solid", |
||||||
|
"version": "1.0.0-alpha.1", |
||||||
|
"description": "A plugin for @ldo/connected to work with the Solid ecosystem.", |
||||||
|
"main": "dist/index.js", |
||||||
|
"scripts": { |
||||||
|
"build": "tsc --project tsconfig.build.json", |
||||||
|
"watch": "tsc --watch", |
||||||
|
"test": "jest --coverage", |
||||||
|
"test:watch": "jest --watch", |
||||||
|
"prepublishOnly": "npm run test && npm run build", |
||||||
|
"lint": "eslint src/** --fix --no-error-on-unmatched-pattern", |
||||||
|
"docs": "typedoc --plugin typedoc-plugin-markdown" |
||||||
|
}, |
||||||
|
"repository": { |
||||||
|
"type": "git", |
||||||
|
"url": "git+https://github.com/o-development/ldobjects.git" |
||||||
|
}, |
||||||
|
"author": "Jackson Morgan", |
||||||
|
"license": "MIT", |
||||||
|
"bugs": { |
||||||
|
"url": "https://github.com/o-development/ldobjects/issues" |
||||||
|
}, |
||||||
|
"homepage": "https://github.com/o-development/ldobjects/tree/main/packages/solid#readme", |
||||||
|
"devDependencies": { |
||||||
|
"@inrupt/solid-client-authn-core": "^2.2.6", |
||||||
|
"@ldo/cli": "^1.0.0-alpha.1", |
||||||
|
"@rdfjs/data-model": "^1.2.0", |
||||||
|
"@rdfjs/types": "^1.0.1", |
||||||
|
"@solid-notifications/types": "^0.1.2", |
||||||
|
"@solid/community-server": "^7.1.3", |
||||||
|
"@types/jest": "^27.0.3", |
||||||
|
"cross-env": "^7.0.3", |
||||||
|
"dotenv": "^16.3.1", |
||||||
|
"jest-rdf": "^1.8.0", |
||||||
|
"ts-jest": "^27.1.2", |
||||||
|
"ts-node": "^10.9.1", |
||||||
|
"typed-emitter": "^2.1.0", |
||||||
|
"typedoc": "^0.25.4", |
||||||
|
"typedoc-plugin-markdown": "^3.17.1" |
||||||
|
}, |
||||||
|
"dependencies": { |
||||||
|
"@ldo/dataset": "^1.0.0-alpha.1", |
||||||
|
"@ldo/ldo": "^1.0.0-alpha.1", |
||||||
|
"@ldo/rdf-utils": "^1.0.0-alpha.1", |
||||||
|
"@solid-notifications/subscription": "^0.1.2", |
||||||
|
"cross-fetch": "^3.1.6", |
||||||
|
"http-link-header": "^1.1.1", |
||||||
|
"ws": "^8.18.0" |
||||||
|
}, |
||||||
|
"files": [ |
||||||
|
"dist", |
||||||
|
"src" |
||||||
|
], |
||||||
|
"publishConfig": { |
||||||
|
"access": "public" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
{ |
||||||
|
"extends": "../../tsconfig.base.json", |
||||||
|
"compilerOptions": { |
||||||
|
"outDir": "./dist", |
||||||
|
}, |
||||||
|
"include": ["./src"] |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
{ |
||||||
|
"entryPoints": ["src/index.ts"], |
||||||
|
"out": "docs", |
||||||
|
"allReflectionsHaveOwnDocument": true, |
||||||
|
"hideInPageTOC": true, |
||||||
|
"hideBreadcrumbs": true, |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
{ |
||||||
|
"extends": ["../../.eslintrc"] |
||||||
|
} |
@ -0,0 +1,2 @@ |
|||||||
|
test/data |
||||||
|
node_modules |
@ -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,238 @@ |
|||||||
|
# @ldo/solid |
||||||
|
|
||||||
|
@ldo/solid is a client that implements the Solid specification with the use of Linked Data Objects. |
||||||
|
|
||||||
|
## Installation |
||||||
|
|
||||||
|
Navigate into your project's root folder and run the following command: |
||||||
|
``` |
||||||
|
cd my_project/ |
||||||
|
npx run @ldo/cli init |
||||||
|
``` |
||||||
|
|
||||||
|
Now install the @ldo/solid library |
||||||
|
|
||||||
|
``` |
||||||
|
npm i @ldo/solid |
||||||
|
``` |
||||||
|
|
||||||
|
<details> |
||||||
|
<summary> |
||||||
|
Manual Installation |
||||||
|
</summary> |
||||||
|
|
||||||
|
If you already have generated ShapeTypes, you may install the `@ldo/ldo` and `@ldo/solid` libraries independently. |
||||||
|
|
||||||
|
``` |
||||||
|
npm i @ldo/ldo @ldo/solid |
||||||
|
``` |
||||||
|
</details> |
||||||
|
|
||||||
|
## Simple Examples |
||||||
|
|
||||||
|
Below is a simple example of @ldo/solid. Assume that a ShapeType was previously generated and placed at `./.ldo/foafProfile.shapeTypes`. Also assume we have a shape type for social media at `./.ldo/socialMediaPost.shapeTypes` |
||||||
|
|
||||||
|
```typescript |
||||||
|
import { changeData, commitData, createSolidLdoDataset } from "@ldo/solid"; |
||||||
|
import { fetch, getDefaultSession } from "@inrupt/solid-client-authn-browser"; |
||||||
|
import { FoafProfileShapeType } from "./.ldo/foafProfile.shapeTypes"; |
||||||
|
import { SocialMediaPostShapeType } from "./.ldo/socialMediaPost.shapeTypes"; |
||||||
|
|
||||||
|
async function main() { |
||||||
|
/** |
||||||
|
* =========================================================================== |
||||||
|
* READING DATA FROM A POD |
||||||
|
* =========================================================================== |
||||||
|
*/ |
||||||
|
|
||||||
|
// Before we begin using @ldo/solid. Let's get the WebId of the current user |
||||||
|
const webIdUri = getDefaultSession().info.webId; |
||||||
|
if (!webIdUri) throw new Error("User is not logged in"); |
||||||
|
|
||||||
|
// Now let's proceed with @ldo/solid. Our first step is setting up a |
||||||
|
// SolidLdoDataset. You can think of this dataset as a local store for all the |
||||||
|
// information in the Solidverse. Don't forget to pass the authenticated fetch |
||||||
|
// function to do your queries! |
||||||
|
const solidLdoDataset = createSolidLdoDataset({ fetch }); |
||||||
|
|
||||||
|
// We'll start with getting a representation of our WebId's resource |
||||||
|
const webIdResource = solidLdoDataset.getResource(webIdUri); |
||||||
|
|
||||||
|
// This resource is currently unfetched |
||||||
|
console.log(webIdResource.isUnfetched()); // Logs true |
||||||
|
|
||||||
|
// So let's fetch it! Running the `read` command will make a request to get |
||||||
|
// the WebId. |
||||||
|
const readResult = await webIdResource.read(); |
||||||
|
|
||||||
|
// @ldo/solid will never throw an error. Instead, it will return errors. This |
||||||
|
// design decision was made to force you to handle any errors. It may seem a |
||||||
|
// bit annoying at first, but it will result in more resiliant code. You can |
||||||
|
// easily follow intellisense tooltips to see what kinds of errors each action |
||||||
|
// can throw. |
||||||
|
if (readResult.isError) { |
||||||
|
switch (readResult.type) { |
||||||
|
case "serverError": |
||||||
|
console.error("The solid server had an error:", readResult.message); |
||||||
|
return; |
||||||
|
case "noncompliantPodError": |
||||||
|
console.error("The Pod responded in a way not compliant with the spec"); |
||||||
|
return; |
||||||
|
default: |
||||||
|
console.error("Some other error was detected:", readResult.message); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// When fetching a data resource, read triples will automatically be added to |
||||||
|
// the solidLdoDataset. You can access them using Linked Data Objects. In |
||||||
|
// the following example we're using a Profile Linked Data Object that was |
||||||
|
// generated with the init step. |
||||||
|
const profile = solidLdoDataset |
||||||
|
.usingType(FoafProfileShapeType) |
||||||
|
.fromSubject(webIdUri); |
||||||
|
|
||||||
|
// Now you can read "profile" like any JSON. |
||||||
|
console.log(profile.name); |
||||||
|
|
||||||
|
/** |
||||||
|
* =========================================================================== |
||||||
|
* MODIFYING DATA |
||||||
|
* =========================================================================== |
||||||
|
*/ |
||||||
|
|
||||||
|
// When we want to modify data the first step is to use the `changeData` |
||||||
|
// function. We pass in an object that we want to change (in this case, |
||||||
|
// "profile") as well an a list of any resources to which we want those |
||||||
|
// changes to be applied (in this case, just the webIdResource). This gives |
||||||
|
// us a new variable (conventionally named with a c for "changed") that we can |
||||||
|
// write changes to. |
||||||
|
const cProfile = changeData(profile, webIdResource); |
||||||
|
|
||||||
|
// We can make changes just like it's regular JSON |
||||||
|
cProfile.name = "Captain Cool Dude"; |
||||||
|
|
||||||
|
// Committing data is as easy as running the "commitData" function. |
||||||
|
const commitResult = await commitData(cProfile); |
||||||
|
|
||||||
|
// Remember to check for and handle errors! We'll keep it short this time. |
||||||
|
if (commitResult.isError) throw commitResult; |
||||||
|
|
||||||
|
/** |
||||||
|
* =========================================================================== |
||||||
|
* CREATING NEW RESOURCES |
||||||
|
* =========================================================================== |
||||||
|
*/ |
||||||
|
|
||||||
|
// Let's create some social media posts to be stored on the Solid Pod! |
||||||
|
// Our first step is going to be finding where to place these posts. In the |
||||||
|
// future, there will be advanced ways to determine the location of resources |
||||||
|
// but for now, let's throw it in the root folder. |
||||||
|
|
||||||
|
// But, first, let's find out where the root folder is. We can take our WebId |
||||||
|
// resource and call `getRootContainer`. Let's assume the root container has |
||||||
|
// a URI "https://example.com/" |
||||||
|
const rootContainer = await webIdResource.getRootContainer(); |
||||||
|
if (rootContainer.isError) throw rootContainer; |
||||||
|
|
||||||
|
// Now, let's create a container for our posts |
||||||
|
const createPostContainerResult = |
||||||
|
await rootContainer.createChildIfAbsent("social-posts/"); |
||||||
|
if (createPostContainerResult.isError) throw createPostContainerResult; |
||||||
|
|
||||||
|
// Most results store the affected resource in the "resource" field. This |
||||||
|
// container has the URI "https://example.com/social-posts/" |
||||||
|
const postContainer = createPostContainerResult.resource; |
||||||
|
|
||||||
|
// Now that we have our container, let's make a Post resource! This is a data |
||||||
|
// resource, which means we can put raw Solid Data (RDF) into it. |
||||||
|
const postResourceResult = |
||||||
|
await postContainer.createChildAndOverwrite("post1.ttl"); |
||||||
|
if (postResourceResult.isError) throw postResourceResult; |
||||||
|
const postResource = postResourceResult.resource; |
||||||
|
|
||||||
|
// We can also create binary resources with things like images |
||||||
|
const imageResourceResult = await postContainer.uploadChildAndOverwrite( |
||||||
|
// name of the binary |
||||||
|
"image1.svg", |
||||||
|
// A blob for the binary |
||||||
|
new Blob([`<svg><circle r="9" /></svg>`]), |
||||||
|
// mime type of the binary |
||||||
|
"image/svg+xml", |
||||||
|
); |
||||||
|
if (imageResourceResult.isError) throw imageResourceResult; |
||||||
|
const imageResource = imageResourceResult.resource; |
||||||
|
|
||||||
|
/** |
||||||
|
* =========================================================================== |
||||||
|
* CREATING NEW DATA |
||||||
|
* =========================================================================== |
||||||
|
*/ |
||||||
|
|
||||||
|
// We create data in a similar way to the way we modify data. We can use the |
||||||
|
// "createData" method. |
||||||
|
const cPost = solidLdoDataset.createData( |
||||||
|
// An LDO ShapeType saying that this is a social media psot |
||||||
|
SocialMediaPostShapeType, |
||||||
|
// The URI of the post (in this case we'll make it the same as the resource) |
||||||
|
postResource.uri, |
||||||
|
// The resource we should write it to |
||||||
|
postResource, |
||||||
|
); |
||||||
|
|
||||||
|
// We can add new data |
||||||
|
cPost.text = "Check out this bad svg:"; |
||||||
|
cPost.image = { "@id": imageResource.uri }; |
||||||
|
|
||||||
|
// And now we commit data |
||||||
|
const newDataResult = await commitData(cPost); |
||||||
|
if (newDataResult.isError) throw newDataResult; |
||||||
|
|
||||||
|
/** |
||||||
|
* =========================================================================== |
||||||
|
* DELETING RESOURCES |
||||||
|
* =========================================================================== |
||||||
|
*/ |
||||||
|
|
||||||
|
// Deleting resources can be done with a single method call. In this case, |
||||||
|
// the container will be deleted along with all its contained resources |
||||||
|
const deleteResult = await postContainer.delete(); |
||||||
|
if (deleteResult.isError) throw deleteResult; |
||||||
|
} |
||||||
|
main(); |
||||||
|
``` |
||||||
|
|
||||||
|
## API Details |
||||||
|
|
||||||
|
SolidLdoDataset |
||||||
|
|
||||||
|
- [createSolidLdoDataset](https://ldo.js.org/latest/api/solid/functions/createSolidLdoDataset/) |
||||||
|
- [SolidLdoDataset](https://ldo.js.org/latest/api/solid/classes/SolidLdoDataset/) |
||||||
|
|
||||||
|
Resources (Manage batching requests) |
||||||
|
|
||||||
|
- [LeafUri](https://ldo.js.org/latest/api/solid/types/LeafUri/) |
||||||
|
- [ContainerUri](https://ldo.js.org/latest/api/solid/types/ContainerUri/) |
||||||
|
- [Leaf](https://ldo.js.org/latest/api/solid/classes/Leaf/) |
||||||
|
- [Container](https://ldo.js.org/latest/api/solid/classes/Container/) |
||||||
|
|
||||||
|
Standalone Functions |
||||||
|
|
||||||
|
- [checkRootContainter](https://ldo.js.org/latest/api/solid/functions/checkRootContainer/) |
||||||
|
- [createDataResource](https://ldo.js.org/latest/api/solid/functions/createDataResource/) |
||||||
|
- [deleteResource](https://ldo.js.org/latest/api/solid/functions/deleteResource/) |
||||||
|
- [readResource](https://ldo.js.org/latest/api/solid/functions/readResource/) |
||||||
|
- [updateResource](https://ldo.js.org/latest/api/solid/functions/updateResource/) |
||||||
|
- [uploadResource](https://ldo.js.org/latest/api/solid/functions/uploadResource/) |
||||||
|
|
||||||
|
Data Functions |
||||||
|
- [changeData](https://ldo.js.org/latest/api/solid/functions/changeData/) |
||||||
|
- [commitData](https://ldo.js.org/latest/api/solid/functions/commitData/) |
||||||
|
|
||||||
|
## Sponsorship |
||||||
|
This project was made possible by a grant from NGI Zero Entrust via nlnet. Learn more on the [NLnet project page](https://nlnet.nl/project/SolidUsableApps/). |
||||||
|
|
||||||
|
[<img src="https://nlnet.nl/logo/banner.png" alt="nlnet foundation logo" width="300" />](https://nlnet.nl/) |
||||||
|
[<img src="https://nlnet.nl/image/logos/NGI0Entrust_tag.svg" alt="NGI Zero Entrust Logo" width="300" />](https://nlnet.nl/) |
||||||
|
|
||||||
|
## Liscense |
||||||
|
MIT |
@ -0,0 +1 @@ |
|||||||
|
module.exports = { presets: ["@babel/preset-env"] }; |
@ -0,0 +1,11 @@ |
|||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const sharedConfig = require("../../jest.config.js"); |
||||||
|
module.exports = { |
||||||
|
...sharedConfig, |
||||||
|
rootDir: "./", |
||||||
|
setupFiles: ["<rootDir>/test/setup-tests.ts"], |
||||||
|
transform: { |
||||||
|
"^.+\\.(ts|tsx)?$": "ts-jest", |
||||||
|
"^.+\\.(js|jsx)$": "babel-jest", |
||||||
|
}, |
||||||
|
}; |
@ -0,0 +1,58 @@ |
|||||||
|
{ |
||||||
|
"name": "@ldo/connected-solid", |
||||||
|
"version": "1.0.0-alpha.1", |
||||||
|
"description": "A plugin for @ldo/connected to work with the Solid ecosystem.", |
||||||
|
"main": "dist/index.js", |
||||||
|
"scripts": { |
||||||
|
"build": "tsc --project tsconfig.build.json", |
||||||
|
"watch": "tsc --watch", |
||||||
|
"test": "jest --coverage", |
||||||
|
"test:watch": "jest --watch", |
||||||
|
"prepublishOnly": "npm run test && npm run build", |
||||||
|
"lint": "eslint src/** --fix --no-error-on-unmatched-pattern", |
||||||
|
"docs": "typedoc --plugin typedoc-plugin-markdown" |
||||||
|
}, |
||||||
|
"repository": { |
||||||
|
"type": "git", |
||||||
|
"url": "git+https://github.com/o-development/ldobjects.git" |
||||||
|
}, |
||||||
|
"author": "Jackson Morgan", |
||||||
|
"license": "MIT", |
||||||
|
"bugs": { |
||||||
|
"url": "https://github.com/o-development/ldobjects/issues" |
||||||
|
}, |
||||||
|
"homepage": "https://github.com/o-development/ldobjects/tree/main/packages/solid#readme", |
||||||
|
"devDependencies": { |
||||||
|
"@inrupt/solid-client-authn-core": "^2.2.6", |
||||||
|
"@ldo/cli": "^1.0.0-alpha.1", |
||||||
|
"@rdfjs/data-model": "^1.2.0", |
||||||
|
"@rdfjs/types": "^1.0.1", |
||||||
|
"@solid-notifications/types": "^0.1.2", |
||||||
|
"@solid/community-server": "^7.1.3", |
||||||
|
"@types/jest": "^27.0.3", |
||||||
|
"cross-env": "^7.0.3", |
||||||
|
"dotenv": "^16.3.1", |
||||||
|
"jest-rdf": "^1.8.0", |
||||||
|
"ts-jest": "^27.1.2", |
||||||
|
"ts-node": "^10.9.1", |
||||||
|
"typed-emitter": "^2.1.0", |
||||||
|
"typedoc": "^0.25.4", |
||||||
|
"typedoc-plugin-markdown": "^3.17.1" |
||||||
|
}, |
||||||
|
"dependencies": { |
||||||
|
"@ldo/dataset": "^1.0.0-alpha.1", |
||||||
|
"@ldo/ldo": "^1.0.0-alpha.1", |
||||||
|
"@ldo/rdf-utils": "^1.0.0-alpha.1", |
||||||
|
"@solid-notifications/subscription": "^0.1.2", |
||||||
|
"cross-fetch": "^3.1.6", |
||||||
|
"http-link-header": "^1.1.1", |
||||||
|
"ws": "^8.18.0" |
||||||
|
}, |
||||||
|
"files": [ |
||||||
|
"dist", |
||||||
|
"src" |
||||||
|
], |
||||||
|
"publishConfig": { |
||||||
|
"access": "public" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
{ |
||||||
|
"extends": "../../tsconfig.base.json", |
||||||
|
"compilerOptions": { |
||||||
|
"outDir": "./dist", |
||||||
|
}, |
||||||
|
"include": ["./src"] |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
{ |
||||||
|
"entryPoints": ["src/index.ts"], |
||||||
|
"out": "docs", |
||||||
|
"allReflectionsHaveOwnDocument": true, |
||||||
|
"hideInPageTOC": true, |
||||||
|
"hideBreadcrumbs": true, |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
{ |
||||||
|
"extends": ["../../.eslintrc"] |
||||||
|
} |
@ -0,0 +1,2 @@ |
|||||||
|
test/data |
||||||
|
node_modules |
@ -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,238 @@ |
|||||||
|
# @ldo/solid |
||||||
|
|
||||||
|
@ldo/solid is a client that implements the Solid specification with the use of Linked Data Objects. |
||||||
|
|
||||||
|
## Installation |
||||||
|
|
||||||
|
Navigate into your project's root folder and run the following command: |
||||||
|
``` |
||||||
|
cd my_project/ |
||||||
|
npx run @ldo/cli init |
||||||
|
``` |
||||||
|
|
||||||
|
Now install the @ldo/solid library |
||||||
|
|
||||||
|
``` |
||||||
|
npm i @ldo/solid |
||||||
|
``` |
||||||
|
|
||||||
|
<details> |
||||||
|
<summary> |
||||||
|
Manual Installation |
||||||
|
</summary> |
||||||
|
|
||||||
|
If you already have generated ShapeTypes, you may install the `@ldo/ldo` and `@ldo/solid` libraries independently. |
||||||
|
|
||||||
|
``` |
||||||
|
npm i @ldo/ldo @ldo/solid |
||||||
|
``` |
||||||
|
</details> |
||||||
|
|
||||||
|
## Simple Examples |
||||||
|
|
||||||
|
Below is a simple example of @ldo/solid. Assume that a ShapeType was previously generated and placed at `./.ldo/foafProfile.shapeTypes`. Also assume we have a shape type for social media at `./.ldo/socialMediaPost.shapeTypes` |
||||||
|
|
||||||
|
```typescript |
||||||
|
import { changeData, commitData, createSolidLdoDataset } from "@ldo/solid"; |
||||||
|
import { fetch, getDefaultSession } from "@inrupt/solid-client-authn-browser"; |
||||||
|
import { FoafProfileShapeType } from "./.ldo/foafProfile.shapeTypes"; |
||||||
|
import { SocialMediaPostShapeType } from "./.ldo/socialMediaPost.shapeTypes"; |
||||||
|
|
||||||
|
async function main() { |
||||||
|
/** |
||||||
|
* =========================================================================== |
||||||
|
* READING DATA FROM A POD |
||||||
|
* =========================================================================== |
||||||
|
*/ |
||||||
|
|
||||||
|
// Before we begin using @ldo/solid. Let's get the WebId of the current user |
||||||
|
const webIdUri = getDefaultSession().info.webId; |
||||||
|
if (!webIdUri) throw new Error("User is not logged in"); |
||||||
|
|
||||||
|
// Now let's proceed with @ldo/solid. Our first step is setting up a |
||||||
|
// SolidLdoDataset. You can think of this dataset as a local store for all the |
||||||
|
// information in the Solidverse. Don't forget to pass the authenticated fetch |
||||||
|
// function to do your queries! |
||||||
|
const solidLdoDataset = createSolidLdoDataset({ fetch }); |
||||||
|
|
||||||
|
// We'll start with getting a representation of our WebId's resource |
||||||
|
const webIdResource = solidLdoDataset.getResource(webIdUri); |
||||||
|
|
||||||
|
// This resource is currently unfetched |
||||||
|
console.log(webIdResource.isUnfetched()); // Logs true |
||||||
|
|
||||||
|
// So let's fetch it! Running the `read` command will make a request to get |
||||||
|
// the WebId. |
||||||
|
const readResult = await webIdResource.read(); |
||||||
|
|
||||||
|
// @ldo/solid will never throw an error. Instead, it will return errors. This |
||||||
|
// design decision was made to force you to handle any errors. It may seem a |
||||||
|
// bit annoying at first, but it will result in more resiliant code. You can |
||||||
|
// easily follow intellisense tooltips to see what kinds of errors each action |
||||||
|
// can throw. |
||||||
|
if (readResult.isError) { |
||||||
|
switch (readResult.type) { |
||||||
|
case "serverError": |
||||||
|
console.error("The solid server had an error:", readResult.message); |
||||||
|
return; |
||||||
|
case "noncompliantPodError": |
||||||
|
console.error("The Pod responded in a way not compliant with the spec"); |
||||||
|
return; |
||||||
|
default: |
||||||
|
console.error("Some other error was detected:", readResult.message); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// When fetching a data resource, read triples will automatically be added to |
||||||
|
// the solidLdoDataset. You can access them using Linked Data Objects. In |
||||||
|
// the following example we're using a Profile Linked Data Object that was |
||||||
|
// generated with the init step. |
||||||
|
const profile = solidLdoDataset |
||||||
|
.usingType(FoafProfileShapeType) |
||||||
|
.fromSubject(webIdUri); |
||||||
|
|
||||||
|
// Now you can read "profile" like any JSON. |
||||||
|
console.log(profile.name); |
||||||
|
|
||||||
|
/** |
||||||
|
* =========================================================================== |
||||||
|
* MODIFYING DATA |
||||||
|
* =========================================================================== |
||||||
|
*/ |
||||||
|
|
||||||
|
// When we want to modify data the first step is to use the `changeData` |
||||||
|
// function. We pass in an object that we want to change (in this case, |
||||||
|
// "profile") as well an a list of any resources to which we want those |
||||||
|
// changes to be applied (in this case, just the webIdResource). This gives |
||||||
|
// us a new variable (conventionally named with a c for "changed") that we can |
||||||
|
// write changes to. |
||||||
|
const cProfile = changeData(profile, webIdResource); |
||||||
|
|
||||||
|
// We can make changes just like it's regular JSON |
||||||
|
cProfile.name = "Captain Cool Dude"; |
||||||
|
|
||||||
|
// Committing data is as easy as running the "commitData" function. |
||||||
|
const commitResult = await commitData(cProfile); |
||||||
|
|
||||||
|
// Remember to check for and handle errors! We'll keep it short this time. |
||||||
|
if (commitResult.isError) throw commitResult; |
||||||
|
|
||||||
|
/** |
||||||
|
* =========================================================================== |
||||||
|
* CREATING NEW RESOURCES |
||||||
|
* =========================================================================== |
||||||
|
*/ |
||||||
|
|
||||||
|
// Let's create some social media posts to be stored on the Solid Pod! |
||||||
|
// Our first step is going to be finding where to place these posts. In the |
||||||
|
// future, there will be advanced ways to determine the location of resources |
||||||
|
// but for now, let's throw it in the root folder. |
||||||
|
|
||||||
|
// But, first, let's find out where the root folder is. We can take our WebId |
||||||
|
// resource and call `getRootContainer`. Let's assume the root container has |
||||||
|
// a URI "https://example.com/" |
||||||
|
const rootContainer = await webIdResource.getRootContainer(); |
||||||
|
if (rootContainer.isError) throw rootContainer; |
||||||
|
|
||||||
|
// Now, let's create a container for our posts |
||||||
|
const createPostContainerResult = |
||||||
|
await rootContainer.createChildIfAbsent("social-posts/"); |
||||||
|
if (createPostContainerResult.isError) throw createPostContainerResult; |
||||||
|
|
||||||
|
// Most results store the affected resource in the "resource" field. This |
||||||
|
// container has the URI "https://example.com/social-posts/" |
||||||
|
const postContainer = createPostContainerResult.resource; |
||||||
|
|
||||||
|
// Now that we have our container, let's make a Post resource! This is a data |
||||||
|
// resource, which means we can put raw Solid Data (RDF) into it. |
||||||
|
const postResourceResult = |
||||||
|
await postContainer.createChildAndOverwrite("post1.ttl"); |
||||||
|
if (postResourceResult.isError) throw postResourceResult; |
||||||
|
const postResource = postResourceResult.resource; |
||||||
|
|
||||||
|
// We can also create binary resources with things like images |
||||||
|
const imageResourceResult = await postContainer.uploadChildAndOverwrite( |
||||||
|
// name of the binary |
||||||
|
"image1.svg", |
||||||
|
// A blob for the binary |
||||||
|
new Blob([`<svg><circle r="9" /></svg>`]), |
||||||
|
// mime type of the binary |
||||||
|
"image/svg+xml", |
||||||
|
); |
||||||
|
if (imageResourceResult.isError) throw imageResourceResult; |
||||||
|
const imageResource = imageResourceResult.resource; |
||||||
|
|
||||||
|
/** |
||||||
|
* =========================================================================== |
||||||
|
* CREATING NEW DATA |
||||||
|
* =========================================================================== |
||||||
|
*/ |
||||||
|
|
||||||
|
// We create data in a similar way to the way we modify data. We can use the |
||||||
|
// "createData" method. |
||||||
|
const cPost = solidLdoDataset.createData( |
||||||
|
// An LDO ShapeType saying that this is a social media psot |
||||||
|
SocialMediaPostShapeType, |
||||||
|
// The URI of the post (in this case we'll make it the same as the resource) |
||||||
|
postResource.uri, |
||||||
|
// The resource we should write it to |
||||||
|
postResource, |
||||||
|
); |
||||||
|
|
||||||
|
// We can add new data |
||||||
|
cPost.text = "Check out this bad svg:"; |
||||||
|
cPost.image = { "@id": imageResource.uri }; |
||||||
|
|
||||||
|
// And now we commit data |
||||||
|
const newDataResult = await commitData(cPost); |
||||||
|
if (newDataResult.isError) throw newDataResult; |
||||||
|
|
||||||
|
/** |
||||||
|
* =========================================================================== |
||||||
|
* DELETING RESOURCES |
||||||
|
* =========================================================================== |
||||||
|
*/ |
||||||
|
|
||||||
|
// Deleting resources can be done with a single method call. In this case, |
||||||
|
// the container will be deleted along with all its contained resources |
||||||
|
const deleteResult = await postContainer.delete(); |
||||||
|
if (deleteResult.isError) throw deleteResult; |
||||||
|
} |
||||||
|
main(); |
||||||
|
``` |
||||||
|
|
||||||
|
## API Details |
||||||
|
|
||||||
|
SolidLdoDataset |
||||||
|
|
||||||
|
- [createSolidLdoDataset](https://ldo.js.org/latest/api/solid/functions/createSolidLdoDataset/) |
||||||
|
- [SolidLdoDataset](https://ldo.js.org/latest/api/solid/classes/SolidLdoDataset/) |
||||||
|
|
||||||
|
Resources (Manage batching requests) |
||||||
|
|
||||||
|
- [LeafUri](https://ldo.js.org/latest/api/solid/types/LeafUri/) |
||||||
|
- [ContainerUri](https://ldo.js.org/latest/api/solid/types/ContainerUri/) |
||||||
|
- [Leaf](https://ldo.js.org/latest/api/solid/classes/Leaf/) |
||||||
|
- [Container](https://ldo.js.org/latest/api/solid/classes/Container/) |
||||||
|
|
||||||
|
Standalone Functions |
||||||
|
|
||||||
|
- [checkRootContainter](https://ldo.js.org/latest/api/solid/functions/checkRootContainer/) |
||||||
|
- [createDataResource](https://ldo.js.org/latest/api/solid/functions/createDataResource/) |
||||||
|
- [deleteResource](https://ldo.js.org/latest/api/solid/functions/deleteResource/) |
||||||
|
- [readResource](https://ldo.js.org/latest/api/solid/functions/readResource/) |
||||||
|
- [updateResource](https://ldo.js.org/latest/api/solid/functions/updateResource/) |
||||||
|
- [uploadResource](https://ldo.js.org/latest/api/solid/functions/uploadResource/) |
||||||
|
|
||||||
|
Data Functions |
||||||
|
- [changeData](https://ldo.js.org/latest/api/solid/functions/changeData/) |
||||||
|
- [commitData](https://ldo.js.org/latest/api/solid/functions/commitData/) |
||||||
|
|
||||||
|
## Sponsorship |
||||||
|
This project was made possible by a grant from NGI Zero Entrust via nlnet. Learn more on the [NLnet project page](https://nlnet.nl/project/SolidUsableApps/). |
||||||
|
|
||||||
|
[<img src="https://nlnet.nl/logo/banner.png" alt="nlnet foundation logo" width="300" />](https://nlnet.nl/) |
||||||
|
[<img src="https://nlnet.nl/image/logos/NGI0Entrust_tag.svg" alt="NGI Zero Entrust Logo" width="300" />](https://nlnet.nl/) |
||||||
|
|
||||||
|
## Liscense |
||||||
|
MIT |
@ -0,0 +1 @@ |
|||||||
|
module.exports = { presets: ["@babel/preset-env"] }; |
@ -0,0 +1,11 @@ |
|||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const sharedConfig = require("../../jest.config.js"); |
||||||
|
module.exports = { |
||||||
|
...sharedConfig, |
||||||
|
rootDir: "./", |
||||||
|
setupFiles: ["<rootDir>/test/setup-tests.ts"], |
||||||
|
transform: { |
||||||
|
"^.+\\.(ts|tsx)?$": "ts-jest", |
||||||
|
"^.+\\.(js|jsx)$": "babel-jest", |
||||||
|
}, |
||||||
|
}; |
@ -0,0 +1,58 @@ |
|||||||
|
{ |
||||||
|
"name": "@ldo/connected", |
||||||
|
"version": "1.0.0-alpha.1", |
||||||
|
"description": "A library for connecting LDO to resources outside the LDO environment", |
||||||
|
"main": "dist/index.js", |
||||||
|
"scripts": { |
||||||
|
"build": "tsc --project tsconfig.build.json", |
||||||
|
"watch": "tsc --watch", |
||||||
|
"test": "jest --coverage", |
||||||
|
"test:watch": "jest --watch", |
||||||
|
"prepublishOnly": "npm run test && npm run build", |
||||||
|
"lint": "eslint src/** --fix --no-error-on-unmatched-pattern", |
||||||
|
"docs": "typedoc --plugin typedoc-plugin-markdown" |
||||||
|
}, |
||||||
|
"repository": { |
||||||
|
"type": "git", |
||||||
|
"url": "git+https://github.com/o-development/ldobjects.git" |
||||||
|
}, |
||||||
|
"author": "Jackson Morgan", |
||||||
|
"license": "MIT", |
||||||
|
"bugs": { |
||||||
|
"url": "https://github.com/o-development/ldobjects/issues" |
||||||
|
}, |
||||||
|
"homepage": "https://github.com/o-development/ldobjects/tree/main/packages/solid#readme", |
||||||
|
"devDependencies": { |
||||||
|
"@inrupt/solid-client-authn-core": "^2.2.6", |
||||||
|
"@ldo/cli": "^1.0.0-alpha.1", |
||||||
|
"@rdfjs/data-model": "^1.2.0", |
||||||
|
"@rdfjs/types": "^1.0.1", |
||||||
|
"@solid-notifications/types": "^0.1.2", |
||||||
|
"@solid/community-server": "^7.1.3", |
||||||
|
"@types/jest": "^27.0.3", |
||||||
|
"cross-env": "^7.0.3", |
||||||
|
"dotenv": "^16.3.1", |
||||||
|
"jest-rdf": "^1.8.0", |
||||||
|
"ts-jest": "^27.1.2", |
||||||
|
"ts-node": "^10.9.1", |
||||||
|
"typed-emitter": "^2.1.0", |
||||||
|
"typedoc": "^0.25.4", |
||||||
|
"typedoc-plugin-markdown": "^3.17.1" |
||||||
|
}, |
||||||
|
"dependencies": { |
||||||
|
"@ldo/dataset": "^1.0.0-alpha.1", |
||||||
|
"@ldo/ldo": "^1.0.0-alpha.1", |
||||||
|
"@ldo/rdf-utils": "^1.0.0-alpha.1", |
||||||
|
"@solid-notifications/subscription": "^0.1.2", |
||||||
|
"cross-fetch": "^3.1.6", |
||||||
|
"http-link-header": "^1.1.1", |
||||||
|
"ws": "^8.18.0" |
||||||
|
}, |
||||||
|
"files": [ |
||||||
|
"dist", |
||||||
|
"src" |
||||||
|
], |
||||||
|
"publishConfig": { |
||||||
|
"access": "public" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
import { LdoDataset } from "@ldo/ldo"; |
||||||
|
import type { ConnectedLdoPlugin } from "./ConnectedLdoPlugin"; |
||||||
|
import type { Dataset, DatasetFactory, Quad } from "@rdfjs/types"; |
||||||
|
import type { ITransactionDatasetFactory } from "@ldo/subscribable-dataset"; |
||||||
|
|
||||||
|
type ReturnTypeFromArgs<T, Arg> = T extends (arg: Arg) => infer R ? R : never; |
||||||
|
|
||||||
|
export class ConnectedLdoDataset< |
||||||
|
Plugins extends ConnectedLdoPlugin[], |
||||||
|
> extends LdoDataset { |
||||||
|
private plugins: Plugins; |
||||||
|
|
||||||
|
constructor( |
||||||
|
plugins: Plugins, |
||||||
|
datasetFactory: DatasetFactory<Quad, Quad>, |
||||||
|
transactionDatasetFactory: ITransactionDatasetFactory<Quad>, |
||||||
|
initialDataset?: Dataset<Quad, Quad>, |
||||||
|
) { |
||||||
|
super(datasetFactory, transactionDatasetFactory, initialDataset); |
||||||
|
this.plugins = plugins; |
||||||
|
} |
||||||
|
|
||||||
|
getResource< |
||||||
|
Name extends Plugins[number]["name"], |
||||||
|
Plugin extends Extract<Plugins[number], { name: Name }>, |
||||||
|
UriType extends Parameters<Plugin["getResource"]>[0], |
||||||
|
>( |
||||||
|
_uri: UriType, |
||||||
|
_pluginName?: Name, |
||||||
|
): ReturnTypeFromArgs<Plugin["getResource"], UriType> { |
||||||
|
return "eh?" as ReturnTypeFromArgs<Plugin["getResource"], UriType>; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,6 @@ |
|||||||
|
import type { Resource } from "./Resource"; |
||||||
|
|
||||||
|
export interface ConnectedLdoPlugin { |
||||||
|
name: string; |
||||||
|
getResource(uri: string): Resource; |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
export interface Resource {} |
||||||
|
|
||||||
|
export class SolidResource implements Resource {} |
||||||
|
export class SolidContainer extends SolidResource {} |
||||||
|
export class SolidLeaf extends SolidResource {} |
||||||
|
|
||||||
|
export class NextGraphResource implements Resource {} |
@ -0,0 +1,55 @@ |
|||||||
|
import { createDatasetFactory } from "@ldo/dataset"; |
||||||
|
import { ConnectedLdoDataset } from "./ConnectedLdoDataset"; |
||||||
|
import { createTransactionDatasetFactory } from "@ldo/subscribable-dataset"; |
||||||
|
import type { ContainerUri, LeafUri } from "../../solid/src/index"; |
||||||
|
import { SolidContainer, SolidLeaf } from "./Resource"; |
||||||
|
|
||||||
|
interface SolidPlugin { |
||||||
|
name: "solid"; |
||||||
|
getResource(uri: ContainerUri): SolidContainer; |
||||||
|
getResource(uri: LeafUri): SolidLeaf; |
||||||
|
getResource(uri: string): SolidLeaf | SolidContainer; |
||||||
|
} |
||||||
|
|
||||||
|
const solidPlugin: SolidPlugin = { |
||||||
|
name: "solid", |
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
getResource(_uri: string): any { |
||||||
|
throw new Error(); |
||||||
|
}, |
||||||
|
}; |
||||||
|
|
||||||
|
interface NextgraphPlugin { |
||||||
|
name: "nextgraph"; |
||||||
|
getResource(uri: ContainerUri); |
||||||
|
getResource(uri: string): "nextgraphResource"; |
||||||
|
} |
||||||
|
|
||||||
|
const nextgraphPlugin: NextgraphPlugin = { |
||||||
|
name: "nextgraph", |
||||||
|
getResource(_uri: string): "nextgraphResource" { |
||||||
|
return "nextgraphResource"; |
||||||
|
}, |
||||||
|
}; |
||||||
|
|
||||||
|
async function main() { |
||||||
|
const dataset = new ConnectedLdoDataset( |
||||||
|
[solidPlugin, nextgraphPlugin], |
||||||
|
createDatasetFactory(), |
||||||
|
createTransactionDatasetFactory(), |
||||||
|
); |
||||||
|
|
||||||
|
const solidContainerResource = dataset.getResource("https://example.com/"); |
||||||
|
const solidLeafResource = dataset.getResource( |
||||||
|
"https://example.com/resource.ttl", |
||||||
|
); |
||||||
|
const stringUri: string = "https://example.com/"; |
||||||
|
const allResources = dataset.getResource(stringUri); |
||||||
|
const solidResource = dataset.getResource(stringUri, "solid"); |
||||||
|
const nextgraphResource = dataset.getResource(stringUri, "nextgraph"); |
||||||
|
|
||||||
|
const nextgraphResource2 = dataset.getResource( |
||||||
|
"did:ng:o:OGNxCWfTXMfYIJi8HCEfL6_uExLtCHrK0JGT4fU5pH4A:v:R2y5iENVwuaaoW86TvMbfZfCIrNXaNIFA3BF6fx9svQA", |
||||||
|
); |
||||||
|
} |
||||||
|
main(); |
@ -0,0 +1,7 @@ |
|||||||
|
{ |
||||||
|
"extends": "../../tsconfig.base.json", |
||||||
|
"compilerOptions": { |
||||||
|
"outDir": "./dist", |
||||||
|
}, |
||||||
|
"include": ["./src"] |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
{ |
||||||
|
"entryPoints": ["src/index.ts"], |
||||||
|
"out": "docs", |
||||||
|
"allReflectionsHaveOwnDocument": true, |
||||||
|
"hideInPageTOC": true, |
||||||
|
"hideBreadcrumbs": true, |
||||||
|
} |
Loading…
Reference in new issue