Login works on the refactor

main
jaxoncreed 2 years ago
parent 0dbe6a5e21
commit a603cc02f4
  1. 132
      package-lock.json
  2. 0
      packages/demo-react/old/BlurTextInput.tsx
  3. 37
      packages/demo-react/old/Layout.tsx
  4. 0
      packages/demo-react/old/Profile.tsx
  5. 1
      packages/demo-react/package.json
  6. 16
      packages/demo-react/src/App.tsx
  7. 77
      packages/demo-react/src/Layout.tsx
  8. 10
      packages/demo-react/src/dashboard/Dashboard.tsx
  9. 12
      packages/demo-react/src/media/Media.tsx
  10. 16
      packages/solid-react/.babelrc
  11. 12
      packages/solid-react/package.json
  12. 96
      packages/solid-react/src/BrowserSolidLdoProvider.tsx
  13. 19
      packages/solid-react/src/LdoContext.ts
  14. 59
      packages/solid-react/src/LdoProvider.tsx
  15. 26
      packages/solid-react/src/SolidAuthContext.ts
  16. 98
      packages/solid-react/src/SolidAuthProvider.ts
  17. 62
      packages/solid-react/src/SolidLdoProvider.tsx
  18. 18
      packages/solid-react/src/documentHooks/useAccessRules.ts
  19. 8
      packages/solid-react/src/documentHooks/useBinaryResource.ts
  20. 11
      packages/solid-react/src/documentHooks/useContainerResource.ts
  21. 8
      packages/solid-react/src/documentHooks/useDataResource.ts
  22. 45
      packages/solid-react/src/documentHooks/useDocument.ts
  23. 16
      packages/solid-react/src/index.ts
  24. 36
      packages/solid-react/src/ldo/solid.context.ts
  25. 214
      packages/solid-react/src/ldo/solid.schema.ts
  26. 28
      packages/solid-react/src/ldo/solid.shapeTypes.ts
  27. 73
      packages/solid-react/src/ldo/solid.typings.ts
  28. 98
      packages/solid-react/src/ldoHooks/helpers/TrackingProxyContext.ts
  29. 76
      packages/solid-react/src/ldoHooks/helpers/UpdateManager.ts
  30. 0
      packages/solid-react/src/ldoHooks/useMatchingObjects.ts
  31. 0
      packages/solid-react/src/ldoHooks/useMatchingSubjects.ts
  32. 59
      packages/solid-react/src/ldoHooks/useSubject.ts
  33. 36
      packages/solid-react/src/shapes/solid.shex
  34. 110
      packages/solid-react/src/useLdo.ts
  35. 2
      packages/solid-react/tsconfig.build.json
  36. 16
      packages/solid/src/SolidLdoDataset.ts
  37. 4
      packages/solid/src/SolidLdoDatasetContext.ts
  38. 5
      packages/solid/src/index.ts
  39. 1
      packages/solid/tsconfig.build.json

132
package-lock.json generated

@ -6706,6 +6706,14 @@
"react-native": "*"
}
},
"node_modules/@remix-run/router": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.8.0.tgz",
"integrity": "sha512-mrfKqIHnSZRyIzBcanNJmVQELTnX+qagEDlcKO90RgRBVOZGSGvZKeDihTRfWcqoDn5N/NkUcwWTccnpN18Tfg==",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@rollup/plugin-babel": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@ -12393,11 +12401,6 @@
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.508.tgz",
"integrity": "sha512-FFa8QKjQK/A5QuFr2167myhMesGrhlOBD+3cYNxO9/S4XzHEXesyTD/1/xF644gC8buFPz3ca6G1LOQD0tZrrg=="
},
"node_modules/emitter-component": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/emitter-component/-/emitter-component-1.1.1.tgz",
"integrity": "sha512-G+mpdiAySMuB7kesVRLuyvYRqDmshB7ReKEVuyBPkzQlmiDiLrt7hHHIy4Aff552bgknVN7B2/d3lzhGO5dvpQ=="
},
"node_modules/emittery": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz",
@ -25330,6 +25333,36 @@
"node": ">=0.10.0"
}
},
"node_modules/react-router": {
"version": "6.15.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.15.0.tgz",
"integrity": "sha512-NIytlzvzLwJkCQj2HLefmeakxxWHWAP+02EGqWEZy+DgfHHKQMUoBBjUQLOtFInBMhWtb3hiUy6MfFgwLjXhqg==",
"dependencies": {
"@remix-run/router": "1.8.0"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/react-router-dom": {
"version": "6.15.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.15.0.tgz",
"integrity": "sha512-aR42t0fs7brintwBGAv2+mGlCtgtFQeOzK0BM1/OiqEzRejOZtpMZepvgkscpMUnKb8YO84G7s3LsHnnDNonbQ==",
"dependencies": {
"@remix-run/router": "1.8.0",
"react-router": "6.15.0"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"react": ">=16.8",
"react-dom": ">=16.8"
}
},
"node_modules/react-shallow-renderer": {
"version": "16.15.0",
"resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz",
@ -27155,14 +27188,6 @@
"node": ">= 0.6"
}
},
"node_modules/stream": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/stream/-/stream-0.0.2.tgz",
"integrity": "sha512-gCq3NDI2P35B2n6t76YJuOp7d6cN/C7Rt0577l91wllh0sY9ZBuw9KaSGqH/b0hzn3CWWJbpbW0W0WvQ1H/Q7g==",
"dependencies": {
"emitter-component": "^1.1.1"
}
},
"node_modules/stream-buffers": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz",
@ -30664,6 +30689,7 @@
"@ldo/solid-react": "^0.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.15.0",
"react-scripts": "5.0.1",
"solid-authn-react-native": "^2.0.3"
},
@ -31275,29 +31301,39 @@
"license": "MIT",
"dependencies": {
"@inrupt/solid-client": "^1.29.0",
"@inrupt/solid-client-authn-browser": "^1.17.1",
"@ldo/dataset": "^0.0.0",
"@ldo/jsonld-dataset-proxy": "^0.0.0",
"@ldo/ldo": "^0.0.0",
"@ldo/solid": "^0.0.0",
"@ldo/subscribable-dataset": "^0.0.0",
"@rdfjs/data-model": "^1.2.0",
"cross-fetch": "^3.1.6",
"solid-authn-react-native": "^2.0.3",
"stream": "^0.0.2"
"cross-fetch": "^3.1.6"
},
"devDependencies": {
"@babel/preset-env": "^7.22.10",
"@babel/preset-react": "^7.22.5",
"@babel/preset-typescript": "^7.22.11",
"@inrupt/solid-client-authn-core": "^1.17.1",
"@ldo/rdf-utils": "^0.0.0",
"@rdfjs/types": "^1.0.1",
"@types/jest": "^29.0.3",
"@types/jsonld": "^1.5.8",
"@types/n3": "^1.10.4",
"@types/shexj": "2.1.4",
"ts-jest": "^29.0.2"
}
},
"packages/solid-react/node_modules/@inrupt/solid-client-authn-browser": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/@inrupt/solid-client-authn-browser/-/solid-client-authn-browser-1.17.1.tgz",
"integrity": "sha512-ApTK9H+v6YOp099opLdyLq9qM5j8adpYkK4KMOQKsK9ndDLVNiduq4EgPq4/jtwPGe0hG0YWuFuB8mJpLzJftA==",
"dependencies": {
"@inrupt/oidc-client-ext": "^1.17.1",
"@inrupt/solid-client-authn-core": "^1.17.1",
"@inrupt/universal-fetch": "^1.0.2",
"events": "^3.3.0",
"jose": "^4.3.7",
"uuid": "^9.0.0"
}
},
"packages/solid-react/node_modules/@jest/console": {
"version": "29.6.4",
"resolved": "https://registry.npmjs.org/@jest/console/-/console-29.6.4.tgz",
@ -38878,6 +38914,7 @@
"@types/shexj": "^2.1.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "*",
"react-scripts": "5.0.1",
"solid-authn-react-native": "^2.0.3",
"tsconfig-paths-webpack-plugin": "^4.1.0"
@ -39245,7 +39282,7 @@
"@types/jest": "^29.0.3",
"cross-fetch": "^3.1.6",
"ts-jest": "^29.0.2",
"typed-emitter": "*"
"typed-emitter": "^2.1.0"
},
"dependencies": {
"@jest/console": {
@ -40165,6 +40202,8 @@
"@babel/preset-react": "^7.22.5",
"@babel/preset-typescript": "^7.22.11",
"@inrupt/solid-client": "^1.29.0",
"@inrupt/solid-client-authn-browser": "^1.17.1",
"@inrupt/solid-client-authn-core": "^1.17.1",
"@ldo/dataset": "^0.0.0",
"@ldo/jsonld-dataset-proxy": "^0.0.0",
"@ldo/ldo": "^0.0.0",
@ -40174,15 +40213,23 @@
"@rdfjs/data-model": "^1.2.0",
"@rdfjs/types": "^1.0.1",
"@types/jest": "^29.0.3",
"@types/jsonld": "^1.5.8",
"@types/n3": "^1.10.4",
"@types/shexj": "2.1.4",
"cross-fetch": "^3.1.6",
"solid-authn-react-native": "^2.0.3",
"stream": "^0.0.2",
"ts-jest": "^29.0.2"
},
"dependencies": {
"@inrupt/solid-client-authn-browser": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/@inrupt/solid-client-authn-browser/-/solid-client-authn-browser-1.17.1.tgz",
"integrity": "sha512-ApTK9H+v6YOp099opLdyLq9qM5j8adpYkK4KMOQKsK9ndDLVNiduq4EgPq4/jtwPGe0hG0YWuFuB8mJpLzJftA==",
"requires": {
"@inrupt/oidc-client-ext": "^1.17.1",
"@inrupt/solid-client-authn-core": "^1.17.1",
"@inrupt/universal-fetch": "^1.0.2",
"events": "^3.3.0",
"jose": "^4.3.7",
"uuid": "^9.0.0"
}
},
"@jest/console": {
"version": "29.6.4",
"resolved": "https://registry.npmjs.org/@jest/console/-/console-29.6.4.tgz",
@ -43230,6 +43277,11 @@
"nullthrows": "^1.1.1"
}
},
"@remix-run/router": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.8.0.tgz",
"integrity": "sha512-mrfKqIHnSZRyIzBcanNJmVQELTnX+qagEDlcKO90RgRBVOZGSGvZKeDihTRfWcqoDn5N/NkUcwWTccnpN18Tfg=="
},
"@rollup/plugin-babel": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@ -47500,11 +47552,6 @@
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.508.tgz",
"integrity": "sha512-FFa8QKjQK/A5QuFr2167myhMesGrhlOBD+3cYNxO9/S4XzHEXesyTD/1/xF644gC8buFPz3ca6G1LOQD0tZrrg=="
},
"emitter-component": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/emitter-component/-/emitter-component-1.1.1.tgz",
"integrity": "sha512-G+mpdiAySMuB7kesVRLuyvYRqDmshB7ReKEVuyBPkzQlmiDiLrt7hHHIy4Aff552bgknVN7B2/d3lzhGO5dvpQ=="
},
"emittery": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz",
@ -57057,6 +57104,23 @@
"integrity": "sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA==",
"peer": true
},
"react-router": {
"version": "6.15.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.15.0.tgz",
"integrity": "sha512-NIytlzvzLwJkCQj2HLefmeakxxWHWAP+02EGqWEZy+DgfHHKQMUoBBjUQLOtFInBMhWtb3hiUy6MfFgwLjXhqg==",
"requires": {
"@remix-run/router": "1.8.0"
}
},
"react-router-dom": {
"version": "6.15.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.15.0.tgz",
"integrity": "sha512-aR42t0fs7brintwBGAv2+mGlCtgtFQeOzK0BM1/OiqEzRejOZtpMZepvgkscpMUnKb8YO84G7s3LsHnnDNonbQ==",
"requires": {
"@remix-run/router": "1.8.0",
"react-router": "6.15.0"
}
},
"react-shallow-renderer": {
"version": "16.15.0",
"resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz",
@ -58472,14 +58536,6 @@
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="
},
"stream": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/stream/-/stream-0.0.2.tgz",
"integrity": "sha512-gCq3NDI2P35B2n6t76YJuOp7d6cN/C7Rt0577l91wllh0sY9ZBuw9KaSGqH/b0hzn3CWWJbpbW0W0WvQ1H/Q7g==",
"requires": {
"emitter-component": "^1.1.1"
}
},
"stream-buffers": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz",

@ -0,0 +1,37 @@
import type { FunctionComponent, PropsWithChildren } from "react";
import React, { useCallback } from "react";
import { useSolidAuth } from "@ldo/solid-react";
const Layout: FunctionComponent<PropsWithChildren> = ({ children }) => {
const { login, session, logout } = useSolidAuth();
const loginCb = useCallback(async () => {
const issuer = prompt(
"Enter your Pod Provider",
"https://solidcommunity.net",
);
if (issuer) {
await login(issuer);
}
}, []);
return (
<div>
<h1>LDO Solid React Test</h1>
{session.isLoggedIn ? (
<div>
<p>
Logged in as {session.webId}{" "}
<button onClick={logout}>Log Out</button>
</p>
<hr />
{children}
</div>
) : (
<button onClick={loginCb}>Log In</button>
)}
</div>
);
};
export default Layout;

@ -6,6 +6,7 @@
"@ldo/solid-react": "^0.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.15.0",
"react-scripts": "5.0.1",
"solid-authn-react-native": "^2.0.3"
},

@ -1,19 +1,13 @@
import type { FunctionComponent } from "react";
import React from "react";
import Profile from "./Profile";
import { SolidAuthProvider, LdoProvider } from "@ldo/solid-react";
import { fetch } from "solid-authn-react-native";
import Layout from "./Layout";
import { Layout } from "./Layout";
import { BrowserSolidLdoProvider } from "@ldo/solid-react";
const ProfileApp: FunctionComponent = () => {
return (
<SolidAuthProvider>
<LdoProvider fetch={fetch}>
<Layout>
<Profile />
</Layout>
</LdoProvider>
</SolidAuthProvider>
<BrowserSolidLdoProvider>
<Layout />
</BrowserSolidLdoProvider>
);
};
export default ProfileApp;

@ -1,37 +1,60 @@
import type { FunctionComponent, PropsWithChildren } from "react";
import React, { useCallback } from "react";
import { useSolidAuth } from "@ldo/solid-react";
import React, { useState } from "react";
import type { FunctionComponent } from "react";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { Dashboard } from "./dashboard/Dashboard";
import { Media } from "./media/Media";
const Layout: FunctionComponent<PropsWithChildren> = ({ children }) => {
const { login, session, logout } = useSolidAuth();
const router = createBrowserRouter([
{
path: "/",
element: <Dashboard />,
},
{
path: "/media/:uri",
element: <Media />,
},
]);
const loginCb = useCallback(async () => {
const issuer = prompt(
"Enter your Pod Provider",
"https://solidcommunity.net",
);
if (issuer) {
await login(issuer);
}
}, []);
const DEFAULT_ISSUER = "https://pod.lightover.com";
export const Layout: FunctionComponent = () => {
const { login, logout, signUp, session, ranInitialAuthCheck } =
useSolidAuth();
const [issuer, setIssuer] = useState(DEFAULT_ISSUER);
console.log(ranInitialAuthCheck);
if (!ranInitialAuthCheck) {
return <p>Loading</p>;
}
return (
<div>
<h1>LDO Solid React Test</h1>
{session.isLoggedIn ? (
<div>
<p>
Logged in as {session.webId}{" "}
<header
style={{
height: 50,
borderBottom: "1px solid black",
display: "flex",
alignItems: "center",
padding: 10,
}}
>
{session.isLoggedIn ? (
<>
<p>Logged in as {session.webId}</p>
<button onClick={logout}>Log Out</button>
</p>
<hr />
{children}
</div>
) : (
<button onClick={loginCb}>Log In</button>
)}
</>
) : (
<>
<input
type="text"
value={issuer}
onChange={(e) => setIssuer(e.target.value)}
/>
<button onClick={() => login(issuer)}>Log In</button>
<button onClick={() => signUp(issuer)}>Sign Up</button>
</>
)}
</header>
{session.isLoggedIn ? <RouterProvider router={router} /> : undefined}
</div>
);
};
export default Layout;

@ -0,0 +1,10 @@
import React from "react";
import type { FunctionComponent } from "react";
export const Dashboard: FunctionComponent = () => {
return (
<div>
<p>Dashboard</p>
</div>
);
};

@ -0,0 +1,12 @@
import React from "react";
import type { FunctionComponent } from "react";
import { useParams } from "react-router-dom";
export const Media: FunctionComponent = () => {
const { uri } = useParams();
return (
<div>
<p>Media: {uri}</p>
</div>
);
};

@ -1,16 +0,0 @@
{
"sourceType": "unambiguous",
"presets": [
[
"@babel/preset-env",
{
"targets": {
"chrome": 100
}
}
],
"@babel/preset-typescript",
"@babel/preset-react"
],
"plugins": []
}

@ -23,27 +23,21 @@
},
"homepage": "https://github.com/o-development/devtool-boilerplate#readme",
"devDependencies": {
"@babel/preset-env": "^7.22.10",
"@babel/preset-react": "^7.22.5",
"@babel/preset-typescript": "^7.22.11",
"@inrupt/solid-client-authn-core": "^1.17.1",
"@ldo/rdf-utils": "^0.0.0",
"@rdfjs/types": "^1.0.1",
"@types/jest": "^29.0.3",
"@types/jsonld": "^1.5.8",
"@types/n3": "^1.10.4",
"@types/shexj": "2.1.4",
"ts-jest": "^29.0.2"
},
"dependencies": {
"@inrupt/solid-client": "^1.29.0",
"@inrupt/solid-client-authn-browser": "^1.17.1",
"@ldo/dataset": "^0.0.0",
"@ldo/jsonld-dataset-proxy": "^0.0.0",
"@ldo/ldo": "^0.0.0",
"@ldo/solid": "^0.0.0",
"@ldo/subscribable-dataset": "^0.0.0",
"@rdfjs/data-model": "^1.2.0",
"cross-fetch": "^3.1.6",
"solid-authn-react-native": "^2.0.3",
"stream": "^0.0.2"
"cross-fetch": "^3.1.6"
}
}

@ -0,0 +1,96 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import type { FunctionComponent, PropsWithChildren } from "react";
import type { LoginOptions, SessionInfo } from "./SolidAuthContext";
import { SolidAuthContext } from "./SolidAuthContext";
import {
getDefaultSession,
handleIncomingRedirect,
login as libraryLogin,
logout as libraryLogout,
fetch as libraryFetch,
} from "@inrupt/solid-client-authn-browser";
const PRE_REDIRECT_URI = "PRE_REDIRECT_URI";
export const BrowserSolidLdoProvider: FunctionComponent<PropsWithChildren> = ({
children,
}) => {
const [session, setSession] = useState<SessionInfo>(getDefaultSession().info);
const [ranInitialAuthCheck, setRanInitialAuthCheck] = useState(false);
const runInitialAuthCheck = useCallback(async () => {
if (!window.localStorage.getItem(PRE_REDIRECT_URI)) {
window.localStorage.setItem(PRE_REDIRECT_URI, window.location.href);
}
await handleIncomingRedirect({
restorePreviousSession: true,
});
setSession({ ...getDefaultSession().info });
window.history.replaceState(
{},
"",
window.localStorage.getItem(PRE_REDIRECT_URI),
);
window.localStorage.removeItem(PRE_REDIRECT_URI);
setRanInitialAuthCheck(true);
}, []);
const login = useCallback(async (issuer: string, options?: LoginOptions) => {
console.log("Before full options");
const fullOptions = {
redirectUrl: window.location.href,
clientName: "Solid App",
oidcIssuer: issuer,
...options,
};
console.log("After full options");
window.localStorage.setItem(PRE_REDIRECT_URI, fullOptions.redirectUrl);
console.log("Set Item");
console.log(fullOptions);
await libraryLogin(fullOptions);
console.log("After login");
setSession({ ...getDefaultSession().info });
}, []);
const logout = useCallback(async () => {
await libraryLogout();
setSession({ ...getDefaultSession().info });
}, []);
const signUp = useCallback(
async (issuer: string, options?: LoginOptions) => {
// The typings on @inrupt/solid-client-authn-core have not yet been updated
// TODO: remove this ts-ignore when they are updated.
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return login(issuer, { ...options, prompt: "create" });
},
[login],
);
useEffect(() => {
runInitialAuthCheck();
}, []);
const solidAuthFunctions = useMemo(
() => ({
runInitialAuthCheck,
login,
logout,
signUp,
session,
ranInitialAuthCheck,
fetch: libraryFetch,
}),
[login, logout, ranInitialAuthCheck, runInitialAuthCheck, session, signUp],
);
return (
<SolidAuthContext.Provider value={solidAuthFunctions}>
{children}
</SolidAuthContext.Provider>
);
};

@ -1,19 +0,0 @@
import { createContext, useContext } from "react";
import type { BinaryResourceStoreDependencies } from "./document/resource/binaryResource/BinaryResourceStore";
import type { DataResourceStoreDependencies } from "./document/resource/dataResource/DataResourceStore";
import type { AccessRulesStoreDependencies } from "./document/accessRules/AccessRulesStore";
import type { ContainerResourceStoreDependencies } from "./document/resource/dataResource/containerResource/ContainerResourceStore";
export interface LdoContextData
extends BinaryResourceStoreDependencies,
DataResourceStoreDependencies,
AccessRulesStoreDependencies,
ContainerResourceStoreDependencies {}
// No default parameter is required as it will be set in the provider
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const LdoContext = createContext<LdoContextData>({});
export const LdoContextProvider = LdoContext.Provider;
export const useLdoContext = () => useContext(LdoContext);

@ -1,59 +0,0 @@
import type { FunctionComponent, PropsWithChildren } from "react";
import React, { useEffect, useMemo } from "react";
import crossFetch from "cross-fetch";
import { createLdoDataset } from "@ldo/ldo";
import type { LdoContextData } from "./LdoContext";
import { LdoContextProvider } from "./LdoContext";
import { UpdateManager } from "./ldoHooks/helpers/UpdateManager";
import type { Dataset } from "@rdfjs/types";
export interface LdoProviderProps extends PropsWithChildren {
fetch?: typeof fetch;
dataset?: Dataset;
onDocumentError?: LdoContextData["onDocumentError"];
}
/**
* Main Ldo Provider
*/
export const LdoProvider: FunctionComponent<
PropsWithChildren<LdoProviderProps>
> = ({ dataset, fetch, onDocumentError, children }) => {
const finalFetch = useMemo(() => fetch || crossFetch, [fetch]);
const ldoDataset = useMemo(() => createLdoDataset(dataset), [dataset]);
// Initialize storeDependencies before render
const storeDependencies = useMemo(() => {
// Ingnoring this because we're setting up circular dependencies
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const dependencies: LdoContextData = {
onDocumentError,
fetch: finalFetch,
dataset: ldoDataset,
updateManager: new UpdateManager(),
};
const binaryResourceStore = new BinaryResourceStore(dependencies);
const dataResourceStore = new DataResourceStore(dependencies);
const containerResourceStore = new ContainerResourceStore(dependencies);
const accessRulesStore = new AccessRulesStore(dependencies);
dependencies.binaryResourceStore = binaryResourceStore;
dependencies.dataResourceStore = dataResourceStore;
dependencies.containerResourceStore = containerResourceStore;
dependencies.accessRulesStore = accessRulesStore;
return dependencies;
}, []);
// Update the resource manager in case fetch or ldo dataset changes
useEffect(() => {
storeDependencies.fetch = finalFetch;
storeDependencies.dataset = ldoDataset;
storeDependencies.onDocumentError = onDocumentError;
}, [finalFetch, ldoDataset, onDocumentError]);
return (
<LdoContextProvider value={storeDependencies}>
{children}
</LdoContextProvider>
);
};

@ -0,0 +1,26 @@
import type {
ISessionInfo,
ILoginInputOptions,
} from "@inrupt/solid-client-authn-core";
import { createContext, useContext } from "react";
export type SessionInfo = ISessionInfo;
export type LoginOptions = ILoginInputOptions;
export interface SolidAuthFunctions {
login: (issuer: string, loginOptions?: LoginOptions) => Promise<void>;
logout: () => Promise<void>;
signUp: (issuer: string, loginOptions?: LoginOptions) => Promise<void>;
fetch: typeof fetch;
session: SessionInfo;
ranInitialAuthCheck: boolean;
}
// There is no initial value for this context. It will be given in the provider
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
export const SolidAuthContext = createContext<SolidAuthFunctions>(undefined);
export function useSolidAuth() {
return useContext(SolidAuthContext);
}

@ -1,98 +0,0 @@
import { useCallback, useEffect, useMemo, useState } from "react";
import type { ISessionInfo } from "solid-authn-react-native";
import {
handleIncomingRedirect,
login as libraryLogin,
getDefaultSession,
logout as libraryLogout,
fetch as libraryFetch,
} from "solid-authn-react-native";
import { createGlobalHook } from "./util/createGlobalHook";
const PRE_REDIRECT_URI = "PRE_REDIRECT_URI";
interface AuthGlobalHookReturn {
runInitialAuthCheck: () => Promise<void>;
login: (issuer: string) => Promise<void>;
logout: () => Promise<void>;
signUp: (issuer: string) => Promise<void>;
fetch: typeof fetch;
session: ISessionInfo;
ranInitialAuthCheck: boolean;
}
function useAuthGlobalHookFunc(): AuthGlobalHookReturn {
const [session, setSession] = useState<ISessionInfo>(
getDefaultSession().info,
);
const [ranInitialAuthCheck, setRanInitialAuthCheck] = useState(false);
const runInitialAuthCheck = useCallback(async () => {
// TODO: Change this to dependency injection so it works in React Native
if (!window.localStorage.getItem(PRE_REDIRECT_URI)) {
window.localStorage.setItem(PRE_REDIRECT_URI, window.location.href);
}
await handleIncomingRedirect({
restorePreviousSession: true,
});
setSession({ ...getDefaultSession().info });
window.history.replaceState(
{},
"",
window.localStorage.getItem(PRE_REDIRECT_URI),
);
window.localStorage.removeItem(PRE_REDIRECT_URI);
setRanInitialAuthCheck(true);
}, []);
const login = useCallback(
async (issuer: string, clientName = "Solid App") => {
window.localStorage.setItem(PRE_REDIRECT_URI, window.location.href);
await libraryLogin({
oidcIssuer: issuer,
// TODO: this ties this to in-browser use
redirectUrl: window.location.href,
clientName,
});
setSession({ ...getDefaultSession().info });
},
[],
);
const logout = useCallback(async () => {
await libraryLogout();
setSession({ ...getDefaultSession().info });
}, []);
const signUp = useCallback(async (issuer: string) => {
/* Do nothing for now */
console.log(`Signup Pressed with issuer ${issuer}`);
}, []);
useEffect(() => {
runInitialAuthCheck();
}, []);
return useMemo(
() => ({
runInitialAuthCheck,
login,
logout,
signUp,
session,
ranInitialAuthCheck,
fetch: libraryFetch,
}),
[login, logout, ranInitialAuthCheck, runInitialAuthCheck, session, signUp],
);
}
const authGlobalHook = createGlobalHook(useAuthGlobalHookFunc);
export const SolidAuthContext = authGlobalHook.Context;
export const SolidAuthProvider = authGlobalHook.Provider;
export const useSolidAuth = authGlobalHook.useGlobal;

@ -0,0 +1,62 @@
import React, { createContext } from "react";
import {
useMemo,
type FunctionComponent,
type PropsWithChildren,
useRef,
useEffect,
} from "react";
import { useSolidAuth } from "./SolidAuthContext";
import type { SolidLdoDataset, OnDocumentErrorCallback } from "@ldo/solid";
import { createSolidLdoDataset } from "@ldo/solid";
export const SolidLdoDatasetReactContext =
// This will be set in the provider
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
createContext<SolidLdoDataset>(undefined);
export interface SolidLdoProviderProps extends PropsWithChildren {
onDocumentError?: OnDocumentErrorCallback;
}
export const SolidLdoProvider: FunctionComponent<SolidLdoProviderProps> = ({
onDocumentError,
children,
}) => {
const { fetch } = useSolidAuth();
const curOnDocumentError = useRef(onDocumentError);
// Initialize storeDependencies before render
const solidLdoDataset = useMemo(() => {
const ldoDataset = createSolidLdoDataset({
fetch,
});
if (curOnDocumentError.current) {
ldoDataset.onDocumentError(curOnDocumentError.current);
}
return ldoDataset;
}, []);
// Keep context in sync with props
useEffect(() => {
solidLdoDataset.context.fetch = fetch;
}, [fetch]);
useEffect(() => {
if (curOnDocumentError.current) {
solidLdoDataset.offDocumentError(curOnDocumentError.current);
}
if (onDocumentError) {
solidLdoDataset.onDocumentError(onDocumentError);
curOnDocumentError.current = onDocumentError;
} else {
curOnDocumentError.current = undefined;
}
}, [onDocumentError]);
return (
<SolidLdoDatasetReactContext.Provider value={solidLdoDataset}>
{children}
</SolidLdoDatasetReactContext.Provider>
);
};

@ -1,18 +0,0 @@
import { useMemo } from "react";
import { useLdoContext } from "../LdoContext";
import type { UseDocumentOptions } from "./useDocument";
import { useDocument } from "./useDocument";
import type { Resource } from "../document/resource/Resource";
export function useAccessRules(
resource: string | Resource,
options?: UseDocumentOptions,
) {
const { dataResourceStore, accessRulesStore } = useLdoContext();
const realResource = useMemo(() => {
return typeof resource === "string"
? dataResourceStore.get(resource)
: resource;
}, [resource]);
return useDocument(realResource, accessRulesStore, options);
}

@ -1,8 +0,0 @@
import { useLdoContext } from "../LdoContext";
import type { UseDocumentOptions } from "./useDocument";
import { useDocument } from "./useDocument";
export function useBinaryResource(uri: string, options?: UseDocumentOptions) {
const { binaryResourceStore } = useLdoContext();
return useDocument(uri, binaryResourceStore, options);
}

@ -1,11 +0,0 @@
import { useLdoContext } from "../LdoContext";
import type { UseDocumentOptions } from "./useDocument";
import { useDocument } from "./useDocument";
export function useContainerResource(
uri: string,
options?: UseDocumentOptions,
) {
const { containerResourceStore } = useLdoContext();
return useDocument(uri, containerResourceStore, options);
}

@ -1,8 +0,0 @@
import { useLdoContext } from "../LdoContext";
import type { UseDocumentOptions } from "./useDocument";
import { useDocument } from "./useDocument";
export function useDataResource(uri: string, options?: UseDocumentOptions) {
const { dataResourceStore } = useLdoContext();
return useDocument(uri, dataResourceStore, options);
}

@ -1,45 +0,0 @@
import { useEffect, useMemo } from "react";
import type {
DocumentStore,
DocumentStoreDependencies,
} from "../document/DocumentStore";
import type { FetchableDocument } from "../document/FetchableDocument";
import { useForceUpdate } from "../util/useForceReload";
export interface UseDocumentOptions {
suppressLoadOnMount: boolean;
}
export function useDocument<
DocumentType extends FetchableDocument,
Initializer,
>(
initializer: Initializer,
documentStore: DocumentStore<
DocumentType,
Initializer,
DocumentStoreDependencies
>,
options?: UseDocumentOptions,
) {
const document = useMemo(() => {
return documentStore.get(initializer);
}, [initializer, documentStore]);
const forceUpdate = useForceUpdate();
useEffect(() => {
// Set up the listener for state update
function onStateUpdateCallback() {
forceUpdate();
}
document.onStateUpdate(onStateUpdateCallback);
// Load the resource if load on mount is true
if (!options?.suppressLoadOnMount) {
document.read();
}
return () => document.offStateUpdate(onStateUpdateCallback);
}, []);
return document;
}

@ -1,14 +1,2 @@
// documentHooks
export * from "./documentHooks/useAccessRules";
export * from "./documentHooks/useBinaryResource";
export * from "./documentHooks/useContainerResource";
export * from "./documentHooks/useDataResource";
export * from "./documentHooks/useDocument";
// ldoHooks
export * from "./ldoHooks/useSubject";
// export
export * from "./useLdo";
export * from "./LdoProvider";
export * from "./SolidAuthProvider";
export * from "./BrowserSolidLdoProvider";
export * from "./SolidAuthContext";

@ -1,36 +0,0 @@
import type { ContextDefinition } from "jsonld";
/**
* =============================================================================
* solidContext: JSONLD Context for solid
* =============================================================================
*/
export const solidContext: ContextDefinition = {
type: {
"@id": "@type",
"@container": "@set",
},
Container: "http://www.w3.org/ns/ldp#Container",
Resource: "http://www.w3.org/ns/ldp#Resource",
modified: {
"@id": "http://purl.org/dc/terms/modified",
"@type": "http://www.w3.org/2001/XMLSchema#string",
"@container": "@set",
},
contains: {
"@id": "http://www.w3.org/ns/ldp#contains",
"@type": "@id",
"@container": "@set",
},
Resource2: "http://www.w3.org/ns/iana/media-types/text/turtle#Resource",
mtime: {
"@id": "http://www.w3.org/ns/posix/stat#mtime",
"@type": "http://www.w3.org/2001/XMLSchema#decimal",
"@container": "@set",
},
size: {
"@id": "http://www.w3.org/ns/posix/stat#size",
"@type": "http://www.w3.org/2001/XMLSchema#integer",
"@container": "@set",
},
};

@ -1,214 +0,0 @@
import type { Schema } from "shexj";
/**
* =============================================================================
* solidSchema: ShexJ Schema for solid
* =============================================================================
*/
export const solidSchema: Schema = {
type: "Schema",
shapes: [
{
id: "http://www.w3.org/ns/lddps#Container",
type: "ShapeDecl",
shapeExpr: {
type: "Shape",
expression: {
id: "http://www.w3.org/ns/lddps#ContainerShape",
type: "EachOf",
expressions: [
{
type: "TripleConstraint",
predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
valueExpr: {
type: "NodeConstraint",
values: [
"http://www.w3.org/ns/ldp#Container",
"http://www.w3.org/ns/ldp#Resource",
],
},
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "A container on a Solid server",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://purl.org/dc/terms/modified",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#string",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "Date modified",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/ldp#contains",
valueExpr: "http://www.w3.org/ns/lddps#Resource",
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "Defines a Solid Resource",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/posix/stat#mtime",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#decimal",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "?",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/posix/stat#size",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#integer",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "size of this container",
},
},
],
},
],
},
extra: ["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"],
},
},
{
id: "http://www.w3.org/ns/lddps#Resource",
type: "ShapeDecl",
shapeExpr: {
type: "Shape",
expression: {
id: "http://www.w3.org/ns/lddps#ResourceShape",
type: "EachOf",
expressions: [
{
type: "TripleConstraint",
predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
valueExpr: {
type: "NodeConstraint",
values: [
"http://www.w3.org/ns/ldp#Resource",
"http://www.w3.org/ns/iana/media-types/text/turtle#Resource",
],
},
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "Any resource on a Solid server",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://purl.org/dc/terms/modified",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#string",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "Date modified",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/posix/stat#mtime",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#decimal",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "?",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/posix/stat#size",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#integer",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "size of this container",
},
},
],
},
],
},
extra: ["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"],
},
},
],
};

@ -1,28 +0,0 @@
import type { ShapeType } from "@ldo/ldo";
import { solidSchema } from "./solid.schema";
import { solidContext } from "./solid.context";
import type { Container, Resource } from "./solid.typings";
/**
* =============================================================================
* LDO ShapeTypes solid
* =============================================================================
*/
/**
* Container ShapeType
*/
export const ContainerShapeType: ShapeType<Container> = {
schema: solidSchema,
shape: "http://www.w3.org/ns/lddps#Container",
context: solidContext,
};
/**
* Resource ShapeType
*/
export const ResourceShapeType: ShapeType<Resource> = {
schema: solidSchema,
shape: "http://www.w3.org/ns/lddps#Resource",
context: solidContext,
};

@ -1,73 +0,0 @@
import type { ContextDefinition } from "jsonld";
/**
* =============================================================================
* Typescript Typings for solid
* =============================================================================
*/
/**
* Container Type
*/
export interface Container {
"@id"?: string;
"@context"?: ContextDefinition;
/**
* A container on a Solid server
*/
type?: (
| {
"@id": "Container";
}
| {
"@id": "Resource";
}
)[];
/**
* Date modified
*/
modified?: string;
/**
* Defines a Solid Resource
*/
contains?: Resource[];
/**
* ?
*/
mtime?: number;
/**
* size of this container
*/
size?: number;
}
/**
* Resource Type
*/
export interface Resource {
"@id"?: string;
"@context"?: ContextDefinition;
/**
* Any resource on a Solid server
*/
type?: (
| {
"@id": "Resource";
}
| {
"@id": "Resource2";
}
)[];
/**
* Date modified
*/
modified?: string;
/**
* ?
*/
mtime?: number;
/**
* size of this container
*/
size?: number;
}

@ -1,98 +0,0 @@
import type {
ArrayProxyTarget,
SubjectProxyTarget,
ProxyContextOptions,
} from "@ldo/jsonld-dataset-proxy";
import { ProxyContext } from "@ldo/jsonld-dataset-proxy";
import type { UpdateManager } from "./UpdateManager";
import { namedNode } from "@rdfjs/data-model";
export class TrackingProxyContext extends ProxyContext {
private updateManager: UpdateManager;
private listener: () => void;
constructor(
options: ProxyContextOptions,
updateManager: UpdateManager,
listener: () => void,
) {
super(options);
this.updateManager = updateManager;
this.listener = listener;
}
protected createSubjectHandler(): ProxyHandler<SubjectProxyTarget> {
const baseHandler = super.createSubjectHandler();
const oldGetFunction = baseHandler.get;
const newGetFunction: ProxyHandler<SubjectProxyTarget>["get"] = (
target: SubjectProxyTarget,
key: string | symbol,
receiver,
) => {
const subject = target["@id"];
if (typeof key === "symbol") {
// Do Nothing
} else if (key === "@id") {
this.updateManager.registerListener(
[subject, null, null, null],
this.listener,
);
} else if (!this.contextUtil.isArray(key)) {
const predicate = namedNode(this.contextUtil.keyToIri(key));
this.updateManager.registerListener(
[subject, predicate, null, null],
this.listener,
);
}
return oldGetFunction && oldGetFunction(target, key, receiver);
};
baseHandler.get = newGetFunction;
baseHandler.set = () => {
console.warn(
"You've attempted to set a value on a Linked Data Object from the useSubject, useMatchingSubject, or useMatchingObject hooks. These linked data objects should only be used to render data, not modify it. To modify data, use the `changeData` function.",
);
return true;
};
return baseHandler;
}
protected createArrayHandler(): ProxyHandler<ArrayProxyTarget> {
const baseHandler = super.createArrayHandler();
const oldGetFunction = baseHandler.get;
const newGetFunction: ProxyHandler<ArrayProxyTarget>["get"] = (
target: ArrayProxyTarget,
key: string | symbol,
receiver,
) => {
if (qualifiedArrayMethods.has(key)) {
this.updateManager.registerListener(
[target[0][0], target[0][1], target[0][2], null],
this.listener,
);
}
return oldGetFunction && oldGetFunction(target, key, receiver);
};
baseHandler.get = newGetFunction;
return baseHandler;
}
}
const qualifiedArrayMethods = new Set([
"forEach",
"map",
"reduce",
Symbol.iterator,
"entries",
"every",
"filter",
"find",
"findIndex",
"findLast",
"findLastIndex",
"includes, indexOf",
"keys",
"lastIndexOf",
"reduceRight",
"some",
"values",
]);

@ -1,76 +0,0 @@
import type {
DatasetChanges,
QuadMatch,
SubjectNode,
PredicateNode,
ObjectNode,
} from "@ldo/rdf-utils";
import { createDataset } from "@ldo/dataset";
import { quadMatchToString } from "@ldo/rdf-utils";
import type { Quad } from "@rdfjs/types";
export class UpdateManager {
private quadMatchListenerMap: Record<string, Set<() => void>> = {};
private listenerHashMap: Map<() => void, Set<string>> = new Map();
registerListener(quadMatch: QuadMatch, callback: () => void): void {
const hash = quadMatchToString(quadMatch);
if (!this.quadMatchListenerMap[hash]) {
this.quadMatchListenerMap[hash] = new Set();
}
if (!this.listenerHashMap.has(callback)) {
this.listenerHashMap.set(callback, new Set());
}
this.quadMatchListenerMap[hash].add(callback);
this.listenerHashMap.get(callback)?.add(hash);
}
removeListener(callback: () => void) {
const hashSet = this.listenerHashMap.get(callback);
if (hashSet) {
hashSet.forEach((hash) => {
this.quadMatchListenerMap[hash]?.delete(callback);
});
}
}
notifyListenersOfChanges(changes: DatasetChanges<Quad>): void {
const listenersToNotify = new Set<() => void>();
const allQuads = createDataset();
allQuads.addAll(changes.added || []);
allQuads.addAll(changes.removed || []);
// Iterate through all quads looking for any dataset match they effect
allQuads.forEach((tempQuad) => {
// Cast the input because RDFJS types assume RDF 1.2 where a Subject can
// be a Quad
const quad = tempQuad as {
subject: SubjectNode;
predicate: PredicateNode;
object: ObjectNode;
};
const quadMatches: QuadMatch[] = [
[null, null, null, null],
[quad.subject, null, null, null],
[quad.subject, quad.predicate, null, null],
[quad.subject, null, quad.object, null],
[null, quad.predicate, null, null],
[null, quad.predicate, quad.object, null],
[null, null, quad.object, null],
[quad.subject, quad.predicate, quad.object, null],
];
quadMatches.forEach((quadMatch) => {
const hash = quadMatchToString(quadMatch);
this.quadMatchListenerMap[hash]?.forEach((callback) => {
listenersToNotify.add(callback);
});
delete this.quadMatchListenerMap[hash];
});
});
listenersToNotify.forEach((listener) => {
listener();
});
}
}

@ -1,59 +0,0 @@
import { defaultGraph } from "@rdfjs/data-model";
import type { SubjectNode } from "@ldo/rdf-utils";
import {
ContextUtil,
JsonldDatasetProxyBuilder,
} from "@ldo/jsonld-dataset-proxy";
import type { ShapeType, LdoBase } from "@ldo/ldo";
import { LdoBuilder } from "@ldo/ldo";
import { useLdoContext } from "../LdoContext";
import { useCallback, useEffect, useMemo, useState } from "react";
import { TrackingProxyContext } from "./helpers/TrackingProxyContext";
export function useSubject<Type extends LdoBase>(
shapeType: ShapeType<Type>,
subject: string | SubjectNode,
): [Type, undefined] | [undefined, Error] {
const { dataset, updateManager } = useLdoContext();
const [forceUpdateCounter, setForceUpdateCounter] = useState(0);
const forceUpdate = useCallback(
() => setForceUpdateCounter((val) => val + 1),
[setForceUpdateCounter],
);
// The main linked data object
const linkedDataObject = useMemo(() => {
// Rebuild the LdoBuilder from scratch to inject TrackingProxyContext
const contextUtil = new ContextUtil(shapeType.context);
const proxyContext = new TrackingProxyContext(
{
dataset,
contextUtil,
writeGraphs: [defaultGraph()],
languageOrdering: ["none", "en", "other"],
},
updateManager,
forceUpdate,
);
const builder = new LdoBuilder(
new JsonldDatasetProxyBuilder(proxyContext),
shapeType,
);
return builder.fromSubject(subject);
}, [
shapeType,
subject,
dataset,
updateManager,
forceUpdateCounter,
forceUpdate,
]);
useEffect(() => {
// Unregister force update listener upon unmount
return () => updateManager.removeListener(forceUpdate);
}, [shapeType, subject]);
return [linkedDataObject, undefined];
}

@ -1,36 +0,0 @@
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX ldp: <http://www.w3.org/ns/ldp#>
PREFIX ldps: <http://www.w3.org/ns/lddps#>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX stat: <http://www.w3.org/ns/posix/stat#>
PREFIX tur: <http://www.w3.org/ns/iana/media-types/text/turtle#>
ldps:Container EXTRA a {
$ldps:ContainerShape (
a [ ldp:Container ldp:Resource ]*
// rdfs:comment "A container on a Solid server";
dct:modified xsd:string?
// rdfs:comment "Date modified";
ldp:contains @ldps:Resource*
// rdfs:comment "Defines a Solid Resource";
stat:mtime xsd:decimal?
// rdfs:comment "?";
stat:size xsd:integer?
// rdfs:comment "size of this container";
)
}
ldps:Resource EXTRA a {
$ldps:ResourceShape (
a [ ldp:Resource tur:Resource ]*
// rdfs:comment "Any resource on a Solid server";
dct:modified xsd:string?
// rdfs:comment "Date modified";
stat:mtime xsd:decimal?
// rdfs:comment "?";
stat:size xsd:integer?
// rdfs:comment "size of this container";
)
}

@ -1,110 +0,0 @@
import { useCallback, useMemo } from "react";
import { useLdoContext } from "./LdoContext";
import type { LdoDataset, ShapeType, LdoBase } from "@ldo/ldo";
import { startTransaction, transactionChanges, write } from "@ldo/ldo";
import { splitChangesByGraph } from "./util/splitChangesByGraph";
import type { Resource } from "./document/resource/Resource";
import type { DataResource } from "./document/resource/dataResource/DataResource";
import type { BinaryResource } from "./document/resource/binaryResource/BinaryResource";
import type { ContainerResource } from "./document/resource/dataResource/containerResource/ContainerResource";
import type { AccessRules } from "./document/accessRules/AccessRules";
import type { DatasetChanges, SubjectNode } from "@ldo/rdf-utils";
import type { Quad } from "@rdfjs/types";
export interface UseLdoReturn {
changeData<Type extends LdoBase>(input: Type, ...resources: Resource[]): Type;
commitData(input: LdoBase): Promise<void>;
createData<Type extends LdoBase>(
shapeType: ShapeType<Type>,
subject: string | SubjectNode,
...resources: Resource[]
): Type;
dataset: LdoDataset;
getDataResource: (uri: string) => DataResource;
getBinaryResource: (uri: string) => BinaryResource;
getContainerResource: (uri: string) => ContainerResource;
getAccessRules: (resource: Resource) => AccessRules;
}
export function useLdo(): UseLdoReturn {
const {
dataResourceStore,
containerResourceStore,
binaryResourceStore,
accessRulesStore,
dataset,
} = useLdoContext();
/**
* Begins tracking changes to eventually commit
*/
const changeData = useCallback(
<Type extends LdoBase>(input: Type, ...resources: Resource[]) => {
// Clone the input and set a graph
const [transactionLdo] = write(...resources.map((r) => r.uri)).usingCopy(
input,
);
// Start a transaction with the input
startTransaction(transactionLdo);
// Return
return transactionLdo;
},
[dataset],
);
/**
* Begins tracking changes to eventually commit for a new subject
*/
const createData = useCallback(
<Type extends LdoBase>(
shapeType: ShapeType<Type>,
subject: string | SubjectType,
...resources: Resource[]
) => {
const linkedDataObject = dataset
.usingType(shapeType)
.write(...resources.map((r) => r.uri))
.fromSubject(subject);
startTransaction(linkedDataObject);
return linkedDataObject;
},
[],
);
/**
* Commits the transaction to the global dataset, syncing all subscribing
* components and Solid Pods
*/
const commitData = useCallback(
async (input: LdoBase) => {
const changes = transactionChanges(input);
const changesByGraph = splitChangesByGraph(
changes as DatasetChanges<Quad>,
);
// Make queries
await Promise.all(
Array.from(changesByGraph.entries()).map(
async ([graph, datasetChanges]) => {
if (graph.termType === "DefaultGraph") {
return;
}
const resource = dataResourceStore.get(graph.value);
await resource.update(datasetChanges);
},
),
);
},
[dataset, fetch],
);
// Returns the values
return useMemo(
() => ({
dataset,
changeData,
createData,
commitData,
getDataResource: (uri) => dataResourceStore.get(uri),
getBinaryResource: (uri) => binaryResourceStore.get(uri),
getContainerResource: (uri) => containerResourceStore.get(uri),
getAccessRules: (resource) => accessRulesStore.get(resource),
}),
[dataset, changeData, commitData],
);
}

@ -2,7 +2,7 @@
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"jsx": "react-jsx"
"lib": ["dom"]
},
"include": ["./src"]
}

@ -6,11 +6,13 @@ import type { BinaryResource } from "./document/resource/binaryResource/BinaryRe
import type { DocumentGetterOptions } from "./document/DocumentStore";
import type { Dataset, DatasetFactory } from "@rdfjs/types";
import type { Resource } from "./document/resource/Resource";
import type { DocumentError } from "./document/errors/DocumentError";
import type { SolidLdoDatasetContext } from "./SolidLdoDatasetContext";
import type {
OnDocumentErrorCallback,
SolidLdoDatasetContext,
} from "./SolidLdoDatasetContext";
export class SolidLdoDataset extends LdoDataset {
protected context: SolidLdoDatasetContext;
public context: SolidLdoDatasetContext;
constructor(
context: SolidLdoDatasetContext,
@ -50,7 +52,11 @@ export class SolidLdoDataset extends LdoDataset {
return this.context.binaryResourceStore.get(uri, options);
}
onDocumentError(_callback: (error: DocumentError) => void): void {
throw new Error("Not Implemented");
onDocumentError(callback: OnDocumentErrorCallback): void {
this.context.documentEventEmitter.on("documentError", callback);
}
offDocumentError(callback: OnDocumentErrorCallback): void {
this.context.documentEventEmitter.off("documentError", callback);
}
}

@ -6,8 +6,10 @@ import type { DataResourceStore } from "./document/resource/dataResource/DataRes
import type { BinaryResourceStore } from "./document/resource/binaryResource/BinaryResourceStore";
import type { DocumentError } from "./document/errors/DocumentError";
export type OnDocumentErrorCallback = (error: DocumentError) => void;
export type DocumentEventEmitter = TypedEmitter<{
documentError: (error: DocumentError) => void;
documentError: OnDocumentErrorCallback;
}>;
export interface SolidLdoDatasetContext {

@ -24,3 +24,8 @@ export * from "./document/resource/dataResource/DataResourceStore";
// document/resource/containerResource
export * from "./document/resource/dataResource/containerResource/ContainerResource";
export * from "./document/resource/dataResource/containerResource/ContainerResourceStore";
// /
export * from "./createSolidLdoDataset";
export * from "./SolidLdoDataset";
export * from "./SolidLdoDatasetContext";

@ -2,7 +2,6 @@
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"jsx": "react-jsx"
},
"include": ["./src"]
}
Loading…
Cancel
Save