Init connected libraries

main
Jackson Morgan 6 months ago
parent d9e4f2c416
commit d896f50c75
  1. 1
      Readme.md
  2. 3
      packages/connected-nextgraph/.eslintrc
  3. 2
      packages/connected-nextgraph/.gitignore
  4. 21
      packages/connected-nextgraph/LICENSE.txt
  5. 238
      packages/connected-nextgraph/README.md
  6. 1
      packages/connected-nextgraph/babel.config.js
  7. 11
      packages/connected-nextgraph/jest.config.js
  8. 58
      packages/connected-nextgraph/package.json
  9. 7
      packages/connected-nextgraph/tsconfig.build.json
  10. 7
      packages/connected-nextgraph/typedoc.json
  11. 3
      packages/connected-solid/.eslintrc
  12. 2
      packages/connected-solid/.gitignore
  13. 21
      packages/connected-solid/LICENSE.txt
  14. 238
      packages/connected-solid/README.md
  15. 1
      packages/connected-solid/babel.config.js
  16. 11
      packages/connected-solid/jest.config.js
  17. 58
      packages/connected-solid/package.json
  18. 7
      packages/connected-solid/tsconfig.build.json
  19. 7
      packages/connected-solid/typedoc.json
  20. 3
      packages/connected/.eslintrc
  21. 2
      packages/connected/.gitignore
  22. 21
      packages/connected/LICENSE.txt
  23. 238
      packages/connected/README.md
  24. 1
      packages/connected/babel.config.js
  25. 11
      packages/connected/jest.config.js
  26. 58
      packages/connected/package.json
  27. 33
      packages/connected/src/ConnectedLdoDataset.ts
  28. 6
      packages/connected/src/ConnectedLdoPlugin.ts
  29. 7
      packages/connected/src/Resource.ts
  30. 55
      packages/connected/src/test.ts
  31. 7
      packages/connected/tsconfig.build.json
  32. 7
      packages/connected/typedoc.json
  33. 1
      packages/solid/src/SolidLdoDataset.ts

@ -15,6 +15,7 @@ The LDO monorepo contains the following
- [@ldo/schema-converter-shex](./packages/schema-converter-shex/) - [@ldo/schema-converter-shex](./packages/schema-converter-shex/)
- [@ldo/solid](./packages/solid/) - [@ldo/solid](./packages/solid/)
- [@ldo/solid-react](./packages/solid-react/) - [@ldo/solid-react](./packages/solid-react/)
- [@ldo/solid-type-index](./packages/solid-type-index/)
- [@ldo/subscribable-dataset](./packages/subscribable-dataset/) - [@ldo/subscribable-dataset](./packages/subscribable-dataset/)
- [@ldo/traverser-shexj](./packages/traverser-shexj/) - [@ldo/traverser-shexj](./packages/traverser-shexj/)
- [@ldo/type-traverser](./packages/type-traverser/) - [@ldo/type-traverser](./packages/type-traverser/)

@ -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,
}

@ -83,7 +83,6 @@ export class SolidLdoDataset extends LdoDataset implements ISolidLdoDataset {
*/ */
getResource(uri: ContainerUri, options?: ResourceGetterOptions): Container; getResource(uri: ContainerUri, options?: ResourceGetterOptions): Container;
getResource(uri: LeafUri, options?: ResourceGetterOptions): Leaf; getResource(uri: LeafUri, options?: ResourceGetterOptions): Leaf;
getResource(uri: string, options?: ResourceGetterOptions): Leaf | Container;
getResource(uri: string, options?: ResourceGetterOptions): Leaf | Container { getResource(uri: string, options?: ResourceGetterOptions): Leaf | Container {
return this.context.resourceStore.get(uri, options); return this.context.resourceStore.get(uri, options);
} }

Loading…
Cancel
Save