diff --git a/package-lock.json b/package-lock.json index c706dbd..f81b6d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10962,11 +10962,22 @@ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, + "node_modules/@types/parse-link-header": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/parse-link-header/-/parse-link-header-2.0.1.tgz", + "integrity": "sha512-BrKNSrRTqn3UkMXvdVtr/znJch0PMBpEvEP8oBkxDx7eEGntuFLI+WpA5HGsNHK4SlqyhaMa+Ks0ViwyixQB5w==" + }, "node_modules/@types/prettier": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==" }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", + "dev": true + }, "node_modules/@types/proper-lockfile": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/@types/proper-lockfile/-/proper-lockfile-4.1.2.tgz", @@ -11024,6 +11035,17 @@ "rdf-js": "^4.0.2" } }, + "node_modules/@types/react": { + "version": "18.2.21", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz", + "integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, "node_modules/@types/readable-stream": { "version": "2.3.15", "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.15.tgz", @@ -11055,6 +11077,12 @@ "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" }, + "node_modules/@types/scheduler": { + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", + "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", + "dev": true + }, "node_modules/@types/semver": { "version": "7.5.1", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.1.tgz", @@ -15207,6 +15235,12 @@ "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" }, + "node_modules/csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", + "dev": true + }, "node_modules/dag-map": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/dag-map/-/dag-map-1.0.2.tgz", @@ -35583,6 +35617,7 @@ "@craco/craco": "^7.1.0", "@ldo/cli": "^0.0.0", "@types/jsonld": "^1.5.9", + "@types/react": "^18.2.21", "@types/shexj": "^2.1.4", "tsconfig-paths-webpack-plugin": "^4.1.0" } @@ -36162,7 +36197,9 @@ "@ldo/dataset": "^0.0.0", "@ldo/ldo": "^0.0.0", "@ldo/rdf-utils": "^0.0.0", + "@types/parse-link-header": "^2.0.1", "cross-fetch": "^3.1.6", + "http-link-header": "^1.1.1", "ts-mixer": "^6.0.3" }, "devDependencies": { @@ -46565,6 +46602,7 @@ "@ldo/cli": "^0.0.0", "@ldo/solid-react": "^0.0.0", "@types/jsonld": "^1.5.9", + "@types/react": "^18.2.21", "@types/shexj": "^2.1.4", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -46931,8 +46969,10 @@ "@rdfjs/types": "^1.0.1", "@solid/community-server": "^6.0.2", "@types/jest": "^29.0.3", + "@types/parse-link-header": "^2.0.1", "cross-fetch": "^3.1.6", "dotenv": "^16.3.1", + "http-link-header": "^1.1.1", "jest-rdf": "^1.8.0", "ts-jest": "^29.0.2", "ts-mixer": "^6.0.3", @@ -52050,11 +52090,22 @@ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, + "@types/parse-link-header": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/parse-link-header/-/parse-link-header-2.0.1.tgz", + "integrity": "sha512-BrKNSrRTqn3UkMXvdVtr/znJch0PMBpEvEP8oBkxDx7eEGntuFLI+WpA5HGsNHK4SlqyhaMa+Ks0ViwyixQB5w==" + }, "@types/prettier": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==" }, + "@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", + "dev": true + }, "@types/proper-lockfile": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/@types/proper-lockfile/-/proper-lockfile-4.1.2.tgz", @@ -52112,6 +52163,17 @@ "rdf-js": "^4.0.2" } }, + "@types/react": { + "version": "18.2.21", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz", + "integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, "@types/readable-stream": { "version": "2.3.15", "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.15.tgz", @@ -52143,6 +52205,12 @@ "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" }, + "@types/scheduler": { + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", + "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", + "dev": true + }, "@types/semver": { "version": "7.5.1", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.1.tgz", @@ -55254,6 +55322,12 @@ } } }, + "csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", + "dev": true + }, "dag-map": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/dag-map/-/dag-map-1.0.2.tgz", diff --git a/packages/demo-react/package.json b/packages/demo-react/package.json index a7a17ed..a804c6e 100644 --- a/packages/demo-react/package.json +++ b/packages/demo-react/package.json @@ -39,6 +39,7 @@ "@craco/craco": "^7.1.0", "@ldo/cli": "^0.0.0", "@types/jsonld": "^1.5.9", + "@types/react": "^18.2.21", "@types/shexj": "^2.1.4", "tsconfig-paths-webpack-plugin": "^4.1.0" } diff --git a/packages/demo-react/src/Layout.tsx b/packages/demo-react/src/Layout.tsx index d2deee0..221bd96 100644 --- a/packages/demo-react/src/Layout.tsx +++ b/packages/demo-react/src/Layout.tsx @@ -4,11 +4,12 @@ import type { FunctionComponent } from "react"; import { createBrowserRouter, RouterProvider } from "react-router-dom"; import { Dashboard } from "./dashboard/Dashboard"; import { Media } from "./media/Media"; +import { BuildRootContainer } from "./dashboard/BuildRootContainer"; const router = createBrowserRouter([ { path: "/", - element: , + element: , }, { path: "/media/:uri", @@ -16,13 +17,12 @@ const router = createBrowserRouter([ }, ]); -const DEFAULT_ISSUER = "https://pod.lightover.com"; +const DEFAULT_ISSUER = "https://solidweb.me"; export const Layout: FunctionComponent = () => { const { login, logout, signUp, session, ranInitialAuthCheck } = useSolidAuth(); const [issuer, setIssuer] = useState(DEFAULT_ISSUER); - console.log(ranInitialAuthCheck); if (!ranInitialAuthCheck) { return

Loading

; } diff --git a/packages/demo-react/src/dashboard/BuildRootContainer.ts b/packages/demo-react/src/dashboard/BuildRootContainer.ts deleted file mode 100644 index 72044a7..0000000 --- a/packages/demo-react/src/dashboard/BuildRootContainer.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { FunctionComponent, PropsWithChildren, ReactNode } from "react"; -import {} from "@ldo/solid"; - -interface BuildRootContainerChildProps { - rootContainer: ContainerResource -} - -export const BuildRootContainer: FunctionComponent<{ children: FunctionComponent }> = () => { - -}; diff --git a/packages/demo-react/src/dashboard/BuildRootContainer.tsx b/packages/demo-react/src/dashboard/BuildRootContainer.tsx new file mode 100644 index 0000000..c4419fa --- /dev/null +++ b/packages/demo-react/src/dashboard/BuildRootContainer.tsx @@ -0,0 +1,37 @@ +import React, { useState, useEffect } from "react"; +import type { FunctionComponent } from "react"; +import type { Container, LeafUri } from "@ldo/solid"; +import { useSolidAuth, useLdo } from "@ldo/solid-react"; + +export interface BuildRootContainerChildProps { + rootContainer: Container; +} + +export const BuildRootContainer: FunctionComponent<{ + child: FunctionComponent; +}> = ({ child }) => { + const Child = child; + const [rootContainer, setRootContainer] = useState(); + const { session } = useSolidAuth(); + const { getResource } = useLdo(); + + useEffect(() => { + if (session.webId) { + const webIdResource = getResource(session.webId as LeafUri); + webIdResource.getRootContainer().then((rootContainer) => { + if (rootContainer.type !== "error") { + setRootContainer(rootContainer); + } else { + alert(rootContainer.message); + } + }); + } + }, [session.webId]); + + if (!session.webId || !rootContainer) { + // Return blank screen + return

Loading

; + } + + return ; +}; diff --git a/packages/demo-react/src/dashboard/Dashboard.tsx b/packages/demo-react/src/dashboard/Dashboard.tsx index bb08f53..ca2db02 100644 --- a/packages/demo-react/src/dashboard/Dashboard.tsx +++ b/packages/demo-react/src/dashboard/Dashboard.tsx @@ -1,29 +1,18 @@ -import React, { useCallback, useEffect, useMemo } from "react"; +import React from "react"; import type { FunctionComponent } from "react"; -import { UploadButton } from "./UploadButton"; -import { useContainerResource, useDataResource, useSolidAuth } from "@ldo/solid-react"; -import { AccessRules, ContainerResource } from "@ldo/solid"; +import type { BuildRootContainerChildProps } from "./BuildRootContainer"; -export const Dashboard: FunctionComponent = () => { - const { session } = useSolidAuth(); - - const rootContainer = useRootContainer(session.webId); - const mainContainer = useContainerResource() - // useParentContainer - - useEffect(() => { - if (rootContainer) { - - } - }, [rootContainer]); - - return ( -
-
- -
-
-
{mainContainer.isLoading ? "Loading" : "Not Loading"}
-
- ); +export const Dashboard: FunctionComponent = ({ + rootContainer, +}) => { + return

{rootContainer.uri}

; + // return ( + //
+ //
+ // + //
+ //
+ //
{mainContainer.isLoading ? "Loading" : "Not Loading"}
+ //
+ // ); }; diff --git a/packages/solid-react/src/SolidAuthContext.ts b/packages/solid-react/src/SolidAuthContext.ts index e325d8f..4620b21 100644 --- a/packages/solid-react/src/SolidAuthContext.ts +++ b/packages/solid-react/src/SolidAuthContext.ts @@ -21,6 +21,6 @@ export interface SolidAuthFunctions { // @ts-ignore export const SolidAuthContext = createContext(undefined); -export function useSolidAuth() { +export function useSolidAuth(): SolidAuthFunctions { return useContext(SolidAuthContext); } diff --git a/packages/solid-react/src/SolidLdoProvider.tsx b/packages/solid-react/src/SolidLdoProvider.tsx index dbc6434..9aae7b1 100644 --- a/packages/solid-react/src/SolidLdoProvider.tsx +++ b/packages/solid-react/src/SolidLdoProvider.tsx @@ -3,43 +3,45 @@ import { useMemo, type FunctionComponent, type PropsWithChildren, - useRef, useEffect, } from "react"; import { useSolidAuth } from "./SolidAuthContext"; -import type { SolidLdoDataset, OnDocumentErrorCallback } from "@ldo/solid"; +import type { SolidLdoDataset } from "@ldo/solid"; import { createSolidLdoDataset } from "@ldo/solid"; +import type { LdoBase, ShapeType } from "@ldo/ldo"; +import type { SubjectNode } from "@ldo/rdf-utils"; -export const SolidLdoDatasetReactContext = +export const SolidLdoReactContext = // This will be set in the provider // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - createContext(undefined); + createContext(undefined); -export function useSolidLdoDataset() { - return useContext(SolidLdoDatasetReactContext); +export interface UseLdoResult { + dataset: SolidLdoDataset; + getResource: SolidLdoDataset["getResource"]; + getSubject( + shapeType: ShapeType, + subject: string | SubjectNode, + ): Type | Error; } -export interface SolidLdoProviderProps extends PropsWithChildren { - onDocumentError?: OnDocumentErrorCallback; +export function useLdo(): UseLdoResult { + return useContext(SolidLdoReactContext); } +export interface SolidLdoProviderProps extends PropsWithChildren {} + export const SolidLdoProvider: FunctionComponent = ({ - onDocumentError, children, }) => { const { fetch } = useSolidAuth(); - const curOnDocumentError = useRef(onDocumentError); // Initialize storeDependencies before render - const solidLdoDataset = useMemo(() => { + const solidLdoDataset: SolidLdoDataset = useMemo(() => { const ldoDataset = createSolidLdoDataset({ fetch, }); - if (curOnDocumentError.current) { - ldoDataset.onDocumentError(curOnDocumentError.current); - } - console.log("ldodatset1", ldoDataset); return ldoDataset; }, []); @@ -47,22 +49,24 @@ export const SolidLdoProvider: FunctionComponent = ({ 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]); - console.log("ldoDataset 2", solidLdoDataset); + const value: UseLdoResult = useMemo( + () => ({ + dataset: solidLdoDataset, + getResource: solidLdoDataset.getResource.bind(solidLdoDataset), + getSubject( + shapeType: ShapeType, + subject: string | SubjectNode, + ): Type | Error { + return solidLdoDataset.usingType(shapeType).fromSubject(subject); + }, + }), + [solidLdoDataset], + ); + return ( - + {children} - + ); }; diff --git a/packages/solid-react/src/documentHooks/useAccessRules.ts b/packages/solid-react/src/documentHooks/useAccessRules.ts deleted file mode 100644 index 7ca2fb7..0000000 --- a/packages/solid-react/src/documentHooks/useAccessRules.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { useMemo } from "react"; -import type { UseDocumentOptions } from "./useDocument"; -import { useTrackStateUpdate } from "./useDocument"; -import type { Resource } from "@ldo/solid"; -import { useSolidLdoDataset } from "../SolidLdoProvider"; - -export function useAccessRules( - resource: string | Resource, - options?: UseDocumentOptions, -) { - const solidLdoDataset = useSolidLdoDataset(); - - const document = useMemo(() => { - return solidLdoDataset.getAccessRules(resource); - }, [resource, solidLdoDataset]); - - useTrackStateUpdate(document, options); - - return document; -} diff --git a/packages/solid-react/src/documentHooks/useBinaryResource.ts b/packages/solid-react/src/documentHooks/useBinaryResource.ts deleted file mode 100644 index e1c476e..0000000 --- a/packages/solid-react/src/documentHooks/useBinaryResource.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { useMemo } from "react"; -import { useSolidLdoDataset } from "../SolidLdoProvider"; -import type { UseDocumentOptions } from "./useDocument"; -import { useTrackStateUpdate } from "./useDocument"; - -export function useBinaryResource(uri: string, options?: UseDocumentOptions) { - const solidLdoDataset = useSolidLdoDataset(); - - const document = useMemo(() => { - return solidLdoDataset.getBinaryResource(uri); - }, [uri, solidLdoDataset]); - - useTrackStateUpdate(document, options); - - return document; -} diff --git a/packages/solid-react/src/documentHooks/useContainerResource.ts b/packages/solid-react/src/documentHooks/useContainerResource.ts deleted file mode 100644 index 4aa8158..0000000 --- a/packages/solid-react/src/documentHooks/useContainerResource.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { useMemo } from "react"; -import type { UseDocumentOptions } from "./useDocument"; -import { useTrackStateUpdate } from "./useDocument"; -import { useSolidLdoDataset } from "../SolidLdoProvider"; - -export function useContainerResource( - uri: string, - options?: UseDocumentOptions, -) { - const solidLdoDataset = useSolidLdoDataset(); - - const document = useMemo(() => { - return solidLdoDataset.getContainerResource(uri); - }, [uri, solidLdoDataset]); - - useTrackStateUpdate(document, options); - - return document; -} diff --git a/packages/solid-react/src/documentHooks/useDataResource.ts b/packages/solid-react/src/documentHooks/useDataResource.ts deleted file mode 100644 index facf40c..0000000 --- a/packages/solid-react/src/documentHooks/useDataResource.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { useMemo } from "react"; -import { useSolidLdoDataset } from "../SolidLdoProvider"; -import type { UseDocumentOptions } from "./useDocument"; -import { useTrackStateUpdate } from "./useDocument"; - -export function useDataResource(uri: string, options?: UseDocumentOptions) { - const solidLdoDataset = useSolidLdoDataset(); - - const document = useMemo(() => { - return solidLdoDataset.getDataResource(uri); - }, [uri, solidLdoDataset]); - - useTrackStateUpdate(document, options); - - return document; -} diff --git a/packages/solid-react/src/documentHooks/useDocument.ts b/packages/solid-react/src/documentHooks/useDocument.ts deleted file mode 100644 index f90e1bb..0000000 --- a/packages/solid-react/src/documentHooks/useDocument.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { useEffect } from "react"; -import type { FetchableDocument } from "@ldo/solid"; -import { useForceUpdate } from "../util/useForceReload"; - -export interface UseDocumentOptions { - suppressLoadOnMount: boolean; -} - -export function useTrackStateUpdate( - document: FetchableDocument, - options?: UseDocumentOptions, -) { - 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); - }, []); -} diff --git a/packages/solid-react/src/index.ts b/packages/solid-react/src/index.ts index a474dc4..b7e3b83 100644 --- a/packages/solid-react/src/index.ts +++ b/packages/solid-react/src/index.ts @@ -1,8 +1,7 @@ export * from "./BrowserSolidLdoProvider"; export * from "./SolidAuthContext"; +export { useLdo } from "./SolidLdoProvider"; + // documentHooks -export * from "./documentHooks/useAccessRules"; -export * from "./documentHooks/useBinaryResource"; -export * from "./documentHooks/useContainerResource"; -export * from "./documentHooks/useDataResource"; +export * from "./useResource"; diff --git a/packages/solid-react/src/useResource.ts b/packages/solid-react/src/useResource.ts new file mode 100644 index 0000000..bfe048a --- /dev/null +++ b/packages/solid-react/src/useResource.ts @@ -0,0 +1,17 @@ +import { useMemo } from "react"; +import type { + Container, + ContainerUri, + LeafUri, + Resource, + Leaf, +} from "@ldo/solid"; +import { useLdo } from "./SolidLdoProvider"; + +export function useResource(uri: ContainerUri): Container; +export function useResource(uri: LeafUri): Leaf; +export function useResource(uri: string): Resource; +export function useResource(uri: string): Resource { + const { getResource } = useLdo(); + return useMemo(() => getResource(uri), [getResource, uri]); +} diff --git a/packages/solid/package.json b/packages/solid/package.json index 3c5f9c6..4f4a767 100644 --- a/packages/solid/package.json +++ b/packages/solid/package.json @@ -40,7 +40,9 @@ "@ldo/dataset": "^0.0.0", "@ldo/ldo": "^0.0.0", "@ldo/rdf-utils": "^0.0.0", + "@types/parse-link-header": "^2.0.1", "cross-fetch": "^3.1.6", + "http-link-header": "^1.1.1", "ts-mixer": "^6.0.3" } } diff --git a/packages/solid/src/ResourceStore.ts b/packages/solid/src/ResourceStore.ts index 0ad4713..95ba596 100644 --- a/packages/solid/src/ResourceStore.ts +++ b/packages/solid/src/ResourceStore.ts @@ -33,7 +33,7 @@ export class ResourceStore { if (isContainerUri(normalizedUri)) { resource = new Container(normalizedUri, this.context); } else { - resource = new Leaf(normalizedUri, this.context); + resource = new Leaf(normalizedUri as LeafUri, this.context); } this.resourceMap.set(normalizedUri, resource); } diff --git a/packages/solid/src/SolidLdoDataset.ts b/packages/solid/src/SolidLdoDataset.ts index 00def5b..b3f7f29 100644 --- a/packages/solid/src/SolidLdoDataset.ts +++ b/packages/solid/src/SolidLdoDataset.ts @@ -19,9 +19,10 @@ export class SolidLdoDataset extends LdoDataset { this.context = context; } - get(uri: ContainerUri, options?: ResourceGetterOptions): Container; - get(uri: LeafUri, options?: ResourceGetterOptions): Leaf; - get(uri: string, options?: ResourceGetterOptions): Resource { + getResource(uri: ContainerUri, options?: ResourceGetterOptions): Container; + getResource(uri: LeafUri, options?: ResourceGetterOptions): Leaf; + getResource(uri: string, options?: ResourceGetterOptions): Resource; + getResource(uri: string, options?: ResourceGetterOptions): Resource { return this.context.resourceStore.get(uri, options); } } diff --git a/packages/solid/src/index.ts b/packages/solid/src/index.ts index 7a7d1b4..de5e625 100644 --- a/packages/solid/src/index.ts +++ b/packages/solid/src/index.ts @@ -4,3 +4,6 @@ export * from "./SolidLdoDatasetContext"; export * from "./resource/Resource"; export * from "./resource/Container"; +export * from "./resource/Leaf"; + +export * from "./util/uriTypes"; diff --git a/packages/solid/src/requester/ContainerRequester.ts b/packages/solid/src/requester/ContainerRequester.ts index fcceb1f..5ea63a0 100644 --- a/packages/solid/src/requester/ContainerRequester.ts +++ b/packages/solid/src/requester/ContainerRequester.ts @@ -1,3 +1,22 @@ import { Requester } from "./Requester"; +import type { CheckRootResult } from "./requests/checkRootContainer"; +import { checkRootContainer } from "./requests/checkRootContainer"; -export class ContainerRequester extends Requester {} +export const IS_ROOT_CONTAINER_KEY = "isRootContainer"; + +export class ContainerRequester extends Requester { + async isRootContainer(): Promise { + return this.requestBatcher.queueProcess({ + name: IS_ROOT_CONTAINER_KEY, + args: [{ uri: this.uri, fetch: this.context.fetch }], + perform: checkRootContainer, + modifyQueue: (queue, isLoading) => { + if (queue.length === 0) { + return isLoading[IS_ROOT_CONTAINER_KEY]; + } else { + return queue[queue.length - 1].name === IS_ROOT_CONTAINER_KEY; + } + }, + }); + } +} diff --git a/packages/solid/src/requester/requests/checkRootContainer.ts b/packages/solid/src/requester/requests/checkRootContainer.ts new file mode 100644 index 0000000..f71fb67 --- /dev/null +++ b/packages/solid/src/requester/requests/checkRootContainer.ts @@ -0,0 +1,35 @@ +import { + UnexpectedHttpError, + type HttpErrorResultType, +} from "../requestResults/HttpErrorResult"; +import { UnexpectedError } from "../requestResults/ErrorResult"; +import type { RequestParams } from "./requestParams"; +import { parse as parseLinkHeader } from "http-link-header"; + +export type CheckRootResult = boolean | CheckRootResultError; +export type CheckRootResultError = HttpErrorResultType | UnexpectedError; + +export async function checkRootContainer({ + uri, + fetch, +}: Omit): Promise { + try { + // Fetch options to determine the document type + const response = await fetch(uri, { method: "HEAD" }); + const linkHeader = response.headers.get("link"); + if (!linkHeader) { + return new UnexpectedHttpError( + uri, + response, + "No link header present in request.", + ); + } + const parsedLinkHeader = parseLinkHeader(linkHeader); + const types = parsedLinkHeader.get("rel", "type"); + return types.some( + (type) => type.uri === "http://www.w3.org/ns/pim/space#Storage", + ); + } catch (err) { + return UnexpectedError.fromThrown(uri, err); + } +} diff --git a/packages/solid/src/resource/Container.ts b/packages/solid/src/resource/Container.ts index 75ab86c..ab413b6 100644 --- a/packages/solid/src/resource/Container.ts +++ b/packages/solid/src/resource/Container.ts @@ -1,22 +1,51 @@ -import type { Requester } from "../requester/Requester"; +import { ContainerRequester } from "../requester/ContainerRequester"; +import { UnexpectedError } from "../requester/requestResults/ErrorResult"; +import type { CheckRootResultError } from "../requester/requests/checkRootContainer"; +import type { SolidLdoDatasetContext } from "../SolidLdoDatasetContext"; +import { getParentUri } from "../util/rdfUtils"; import type { ContainerUri } from "../util/uriTypes"; import { Resource } from "./Resource"; export class Container extends Resource { - protected requester: Requester; + protected requester: ContainerRequester; + protected rootContainer: boolean | undefined; + readonly type = "container" as const; + + constructor(uri: ContainerUri, context: SolidLdoDatasetContext) { + super(uri, context); + this.requester = new ContainerRequester(uri, context); + } + + isRootContainer(): boolean | undefined { + return this.rootContainer; + } + getParentContainer(): Promise { throw new Error("Method not implemented."); } - getRootContainer(): Promise { - throw new Error("Method not implemented."); + + async getRootContainer(): Promise { + if (this.rootContainer === undefined) { + const rootContainerResult = await this.requester.isRootContainer(); + if (typeof rootContainerResult !== "boolean") { + return rootContainerResult; + } + this.rootContainer = rootContainerResult; + } + if (this.rootContainer) { + return this; + } + const parentUri = getParentUri(this.uri); + if (!parentUri) { + return new UnexpectedError( + this.uri, + new Error("Resource does not have a root container"), + ); + } + return this.context.resourceStore.get(parentUri); } + getMimeType(): string { throw new Error("Method not implemented."); } - readonly uri: ContainerUri; - private rootContainer: boolean | undefined; - - isRootContainer(): boolean | undefined { - return this.rootContainer; - } } diff --git a/packages/solid/src/resource/Leaf.ts b/packages/solid/src/resource/Leaf.ts index 102b260..114337e 100644 --- a/packages/solid/src/resource/Leaf.ts +++ b/packages/solid/src/resource/Leaf.ts @@ -1,20 +1,34 @@ import type { DatasetChanges } from "@ldo/rdf-utils"; +import { LeafRequester } from "../requester/LeafRequester"; import type { Requester } from "../requester/Requester"; +import type { CheckRootResultError } from "../requester/requests/checkRootContainer"; import type { UpdateResultError } from "../requester/requests/updateDataResource"; import type { UploadResultError, UploadResultWithoutOverwriteError, } from "../requester/requests/uploadResource"; +import type { SolidLdoDatasetContext } from "../SolidLdoDatasetContext"; +import { getParentUri } from "../util/rdfUtils"; +import type { LeafUri } from "../util/uriTypes"; import type { Container } from "./Container"; import { Resource } from "./Resource"; export class Leaf extends Resource { protected requester: Requester; + readonly type = "leaf" as const; + + constructor(uri: LeafUri, context: SolidLdoDatasetContext) { + super(uri, context); + this.requester = new LeafRequester(uri, context); + } + getParentContainer(): Promise { throw new Error("Method not implemented."); } - getRootContainer(): Promise { - throw new Error("Method not implemented."); + getRootContainer(): Promise { + const parentUri = getParentUri(this.uri)!; + const parent = this.context.resourceStore.get(parentUri); + return parent.getRootContainer(); } getMimeType(): string { throw new Error("Method not implemented."); diff --git a/packages/solid/src/resource/Resource.ts b/packages/solid/src/resource/Resource.ts index 0deae08..1ff8c74 100644 --- a/packages/solid/src/resource/Resource.ts +++ b/packages/solid/src/resource/Resource.ts @@ -14,11 +14,13 @@ import type { DeleteResultError } from "../requester/requests/deleteResource"; import type { ReadResultError } from "../requester/requests/readResource"; import type { Container } from "./Container"; import type { Requester } from "../requester/Requester"; +import type { CheckRootResultError } from "../requester/requests/checkRootContainer"; export abstract class Resource { // All intance variables protected readonly context: SolidLdoDatasetContext; readonly uri: string; + abstract readonly type: string; protected abstract readonly requester: Requester; protected didInitialFetch: boolean = false; protected absent: boolean | undefined; @@ -89,6 +91,7 @@ export abstract class Resource { data: result.blob, mimeType: result.mimeType, }; + return this; default: return new UnexpectedError( this.uri, @@ -132,7 +135,7 @@ export abstract class Resource { // Parent Container Methods -- Remember to change for Container abstract getParentContainer(): Promise; - abstract getRootContainer(): Promise; + abstract getRootContainer(): Promise; // Exclusing Methods ========================================================= // Data Methods (Data Leaf Only) diff --git a/packages/solid/src/resource/abstract/AbstractResource.ts b/packages/solid/src/resource/abstract/AbstractResource.ts deleted file mode 100644 index 7cd02e2..0000000 --- a/packages/solid/src/resource/abstract/AbstractResource.ts +++ /dev/null @@ -1 +0,0 @@ -export abstract class AbstractResource {} diff --git a/packages/solid/src/resource/abstract/container/AbsentContainer.ts b/packages/solid/src/resource/abstract/container/AbsentContainer.ts deleted file mode 100644 index 35cb8f1..0000000 --- a/packages/solid/src/resource/abstract/container/AbsentContainer.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Mixin } from "ts-mixer"; -import { PresentContainer } from "./PresentContainer"; -import { Absent } from "../fetchStatus/Absent"; - -export class AbsentContainer extends Mixin(PresentContainer, Absent) {} diff --git a/packages/solid/src/resource/abstract/container/AbstractContainer.ts b/packages/solid/src/resource/abstract/container/AbstractContainer.ts deleted file mode 100644 index 7410f25..0000000 --- a/packages/solid/src/resource/abstract/container/AbstractContainer.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { AbstractResource } from "../AbstractResource"; - -export abstract class AbstractContainer extends AbstractResource {} diff --git a/packages/solid/src/resource/abstract/container/FetchedContainer.ts b/packages/solid/src/resource/abstract/container/FetchedContainer.ts deleted file mode 100644 index f179089..0000000 --- a/packages/solid/src/resource/abstract/container/FetchedContainer.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Mixin } from "ts-mixer"; -import { AbstractContainer } from "./AbstractContainer"; -import { Fetched } from "../fetchStatus/Fetched"; - -export abstract class FetchedContainer extends Mixin( - AbstractContainer, - Fetched, -) {} diff --git a/packages/solid/src/resource/abstract/container/PresentContainer.ts b/packages/solid/src/resource/abstract/container/PresentContainer.ts deleted file mode 100644 index 1705e2a..0000000 --- a/packages/solid/src/resource/abstract/container/PresentContainer.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Mixin } from "ts-mixer"; -import { FetchedContainer } from "./FetchedContainer"; -import { Present } from "../fetchStatus/Present"; - -export abstract class PresentContainer extends Mixin( - FetchedContainer, - Present, -) {} diff --git a/packages/solid/src/resource/abstract/container/UnfetchedContainer.ts b/packages/solid/src/resource/abstract/container/UnfetchedContainer.ts deleted file mode 100644 index 90c1ccd..0000000 --- a/packages/solid/src/resource/abstract/container/UnfetchedContainer.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Mixin } from "ts-mixer"; -import { AbstractContainer } from "./AbstractContainer"; -import { Unfetched } from "../fetchStatus/Unfetched"; - -export class UnfetchedContainer extends Mixin(AbstractContainer, Unfetched) {} diff --git a/packages/solid/src/resource/abstract/fetchStatus/Absent.ts b/packages/solid/src/resource/abstract/fetchStatus/Absent.ts deleted file mode 100644 index 1264c82..0000000 --- a/packages/solid/src/resource/abstract/fetchStatus/Absent.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Fetched } from "./Fetched"; - -export abstract class Absent extends Fetched {} diff --git a/packages/solid/src/resource/abstract/fetchStatus/Fetched.ts b/packages/solid/src/resource/abstract/fetchStatus/Fetched.ts deleted file mode 100644 index b123341..0000000 --- a/packages/solid/src/resource/abstract/fetchStatus/Fetched.ts +++ /dev/null @@ -1 +0,0 @@ -export abstract class Fetched {} diff --git a/packages/solid/src/resource/abstract/fetchStatus/Present.ts b/packages/solid/src/resource/abstract/fetchStatus/Present.ts deleted file mode 100644 index 0aa7688..0000000 --- a/packages/solid/src/resource/abstract/fetchStatus/Present.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Fetched } from "./Fetched"; - -export abstract class Present extends Fetched {} diff --git a/packages/solid/src/resource/abstract/fetchStatus/Unfetched.ts b/packages/solid/src/resource/abstract/fetchStatus/Unfetched.ts deleted file mode 100644 index 4d13721..0000000 --- a/packages/solid/src/resource/abstract/fetchStatus/Unfetched.ts +++ /dev/null @@ -1 +0,0 @@ -export abstract class Unfetched {} diff --git a/packages/solid/src/resource/abstract/leaf/AbsentLeaf.ts b/packages/solid/src/resource/abstract/leaf/AbsentLeaf.ts deleted file mode 100644 index 7e1755d..0000000 --- a/packages/solid/src/resource/abstract/leaf/AbsentLeaf.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Mixin } from "ts-mixer"; -import { Absent } from "../fetchStatus/Absent"; -import { FetchedLeaf } from "./FetchedLeaf"; - -export class AbsentLeaf extends Mixin(FetchedLeaf, Absent) {} diff --git a/packages/solid/src/resource/abstract/leaf/AbstractLeaf.ts b/packages/solid/src/resource/abstract/leaf/AbstractLeaf.ts deleted file mode 100644 index 60e0c05..0000000 --- a/packages/solid/src/resource/abstract/leaf/AbstractLeaf.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { AbstractResource } from "../AbstractResource"; - -export abstract class AbstractLeaf extends AbstractResource {} diff --git a/packages/solid/src/resource/abstract/leaf/BinaryLeaf.ts b/packages/solid/src/resource/abstract/leaf/BinaryLeaf.ts deleted file mode 100644 index f1008f6..0000000 --- a/packages/solid/src/resource/abstract/leaf/BinaryLeaf.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { PresentLeaf } from "./PresentLeaf"; - -export class BinaryLeaf extends PresentLeaf {} diff --git a/packages/solid/src/resource/abstract/leaf/DataLeaf.ts b/packages/solid/src/resource/abstract/leaf/DataLeaf.ts deleted file mode 100644 index 6ced3f0..0000000 --- a/packages/solid/src/resource/abstract/leaf/DataLeaf.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { PresentLeaf } from "./PresentLeaf"; - -export class DataLeaf extends PresentLeaf {} diff --git a/packages/solid/src/resource/abstract/leaf/FetchedLeaf.ts b/packages/solid/src/resource/abstract/leaf/FetchedLeaf.ts deleted file mode 100644 index ef8f12c..0000000 --- a/packages/solid/src/resource/abstract/leaf/FetchedLeaf.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Mixin } from "ts-mixer"; -import { AbstractLeaf } from "./AbstractLeaf"; -import { Fetched } from "../fetchStatus/Fetched"; - -export abstract class FetchedLeaf extends Mixin(AbstractLeaf, Fetched) {} diff --git a/packages/solid/src/resource/abstract/leaf/PresentLeaf.ts b/packages/solid/src/resource/abstract/leaf/PresentLeaf.ts deleted file mode 100644 index 500c0a2..0000000 --- a/packages/solid/src/resource/abstract/leaf/PresentLeaf.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Mixin } from "ts-mixer"; -import { FetchedLeaf } from "./FetchedLeaf"; -import { Present } from "../fetchStatus/Present"; - -export abstract class PresentLeaf extends Mixin(FetchedLeaf, Present) {} diff --git a/packages/solid/src/resource/abstract/leaf/UnfetchedLeaf.ts b/packages/solid/src/resource/abstract/leaf/UnfetchedLeaf.ts deleted file mode 100644 index c82a85b..0000000 --- a/packages/solid/src/resource/abstract/leaf/UnfetchedLeaf.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Mixin } from "ts-mixer"; -import { AbstractLeaf } from "./AbstractLeaf"; -import { Unfetched } from "../fetchStatus/Unfetched"; - -export class UnfetchedLeaf extends Mixin(AbstractLeaf, Unfetched) {} diff --git a/packages/solid/src/resource/error/MethodNotAllowedError.ts b/packages/solid/src/resource/error/MethodNotAllowedError.ts deleted file mode 100644 index 2409f21..0000000 --- a/packages/solid/src/resource/error/MethodNotAllowedError.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { ResourceType } from "../abstract/AbstractResource"; -import type { LeafType } from "../abstract/leaf/Leaf"; -import { ResourceError } from "./ResourceError"; - -export class MethodNotAllowedError< - rType extends ResourceType, -> extends ResourceError { - type: "MethodNotAllowed"; - methodName: string; - currentResource: rType; -} - -export class LeafMethodNotAllowedError extends MethodNotAllowedError {} -export class ContainerMethodNotAllowedError extends MethodNotAllowedError {} diff --git a/packages/solid/src/resource/error/ResourceError.ts b/packages/solid/src/resource/error/ResourceError.ts deleted file mode 100644 index 7851a24..0000000 --- a/packages/solid/src/resource/error/ResourceError.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ResourceType } from "../abstract/AbstractResource"; - -export abstract class ResourceError extends Error { - public abstract readonly currentResource: ResourceType; - public abstract readonly type: string; -} diff --git a/packages/solid/src/util/rdfUtils.ts b/packages/solid/src/util/rdfUtils.ts index 6462508..882e393 100644 --- a/packages/solid/src/util/rdfUtils.ts +++ b/packages/solid/src/util/rdfUtils.ts @@ -3,6 +3,7 @@ import { namedNode, quad as createQuad } from "@rdfjs/data-model"; import { DataResult } from "../requester/requestResults/DataResult"; import { TurtleFormattingError } from "../requester/requestResults/DataResult"; import type { Dataset } from "@rdfjs/types"; +import type { ContainerUri } from "./uriTypes"; import { isContainerUri } from "./uriTypes"; const ldpContains = namedNode("http://www.w3.org/ns/ldp#contains"); @@ -11,7 +12,7 @@ const ldpResource = namedNode("http://www.w3.org/ns/ldp#Resource"); const ldpContainer = namedNode("http://www.w3.org/ns/ldp#Container"); const ldpBasicContainer = namedNode("http://www.w3.org/ns/ldp#BasicContainer"); -export function getParentUri(uri: string): string | undefined { +export function getParentUri(uri: string): ContainerUri | undefined { const urlObject = new URL(uri); const pathItems = urlObject.pathname.split("/"); if ( @@ -25,7 +26,7 @@ export function getParentUri(uri: string): string | undefined { } pathItems.pop(); urlObject.pathname = `${pathItems.join("/")}/`; - return urlObject.toString(); + return urlObject.toString() as ContainerUri; } export function getSlug(uri: string): string { diff --git a/packages/solid/test/ContainerRequester.test.ts b/packages/solid/test/ContainerRequester.test.ts new file mode 100644 index 0000000..f8c12d9 --- /dev/null +++ b/packages/solid/test/ContainerRequester.test.ts @@ -0,0 +1,87 @@ +import type { App } from "@solid/community-server"; +import { getAuthenticatedFetch, ROOT_COONTAINER } from "./solidServer.helper"; +import type { SolidLdoDataset } from "../src/SolidLdoDataset"; +import { createSolidLdoDataset } from "../src/createSolidLdoDataset"; +import { ContainerRequester } from "../src/requester/ContainerRequester"; + +describe("Container Requester", () => { + let _app: App; + let authFetch: typeof fetch; + let fetchMock: typeof fetch; + let solidLdoDataset: SolidLdoDataset; + + beforeAll(async () => { + // Start up the server + // app = await createApp(); + // await app.start(); + + authFetch = await getAuthenticatedFetch(); + }); + + beforeEach(async () => { + fetchMock = jest.fn(authFetch); + solidLdoDataset = createSolidLdoDataset({ fetch: fetchMock }); + // Create a new document called sample.ttl + await Promise.all([ + authFetch(`${ROOT_COONTAINER}test_leaf/`, { + method: "POST", + headers: { "content-type": "text/turtle", slug: "sample.ttl" }, + body: `@base . + @prefix rdf: . + @prefix rdfs: . + @prefix foaf: . + @prefix rel: . + + <#green-goblin> + rel:enemyOf <#spiderman> ; + a foaf:Person ; # in the context of the Marvel universe + foaf:name "Green Goblin" . + + <#spiderman> + rel:enemyOf <#green-goblin> ; + a foaf:Person ; + foaf:name "Spiderman", "Человек-паук"@ru .`, + }), + authFetch(`${ROOT_COONTAINER}test_leaf/`, { + method: "PUT", + headers: { "content-type": "text/plain", slug: "sample.txt" }, + body: `some text.`, + }), + ]); + }); + + afterEach(async () => { + await Promise.all([ + authFetch(`${ROOT_COONTAINER}test_leaf/sample.ttl`, { + method: "DELETE", + }), + authFetch(`${ROOT_COONTAINER}test_leaf/sample2.ttl`, { + method: "DELETE", + }), + authFetch(`${ROOT_COONTAINER}test_leaf/sample.txt`, { + method: "DELETE", + }), + authFetch(`${ROOT_COONTAINER}test_leaf/sample2.txt`, { + method: "DELETE", + }), + ]); + }); + + it("Checks if a root container is a root container", async () => { + const leafRequester = new ContainerRequester( + `${ROOT_COONTAINER}`, + solidLdoDataset.context, + ); + const result = await leafRequester.isRootContainer(); + expect(result).toBe(true); + }); + + it("Checks if a non root container is a root container", async () => { + const leafRequester = new ContainerRequester( + `${ROOT_COONTAINER}/test_leaf/`, + solidLdoDataset.context, + ); + const result = await leafRequester.isRootContainer(); + expect(result).toBe(false); + }); +}); diff --git a/packages/solid/test/LeafRequester.test.ts b/packages/solid/test/LeafRequester.test.ts index c763285..fd9a7b9 100644 --- a/packages/solid/test/LeafRequester.test.ts +++ b/packages/solid/test/LeafRequester.test.ts @@ -4,11 +4,9 @@ import type { SolidLdoDataset } from "../src/SolidLdoDataset"; import { createSolidLdoDataset } from "../src/createSolidLdoDataset"; import { LeafRequester } from "../src/requester/LeafRequester"; import { namedNode, quad as createQuad } from "@rdfjs/data-model"; -import type { BinaryResult } from "../src/requester/requestResults/BinaryResult"; -import { Readable } from "stream"; describe("Leaf Requester", () => { - let app: App; + let _app: App; let authFetch: typeof fetch; let fetchMock: typeof fetch; let solidLdoDataset: SolidLdoDataset; @@ -25,7 +23,7 @@ describe("Leaf Requester", () => { fetchMock = jest.fn(authFetch); solidLdoDataset = createSolidLdoDataset({ fetch: fetchMock }); // Create a new document called sample.ttl - const [result] = await Promise.all([ + await Promise.all([ authFetch(`${ROOT_COONTAINER}test_leaf/`, { method: "POST", headers: { "content-type": "text/turtle", slug: "sample.ttl" },