diff --git a/package-lock.json b/package-lock.json index 5ff5913..a4894bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3861,6 +3861,21 @@ "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", "dev": true }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "dev": true + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -3920,18 +3935,6 @@ "node": ">=6.9.0" } }, - "node_modules/@inrupt/jest-jsdom-polyfills": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@inrupt/jest-jsdom-polyfills/-/jest-jsdom-polyfills-3.0.2.tgz", - "integrity": "sha512-/8Op3usHmVx4ylfzgqMgED6QC7hBR9LxoOmhfPbmXXkhOTtCCDXYLhPxUjgWMH0b+kK5k3/H0YLMOaWdoFINPA==", - "dev": true, - "dependencies": { - "@peculiar/webcrypto": "^1.4.0", - "@web-std/blob": "^3.0.5", - "@web-std/file": "^3.0.3", - "undici": "^5.27.2" - } - }, "node_modules/@inrupt/oidc-client": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@inrupt/oidc-client/-/oidc-client-1.11.6.tgz", @@ -5788,45 +5791,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@peculiar/asn1-schema": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.8.tgz", - "integrity": "sha512-ULB1XqHKx1WBU/tTFIA+uARuRoBVZ4pNdOA878RDrRbBfBGcSzi5HBkdScC6ZbHn8z7L8gmKCgPC1LHRrP46tA==", - "dev": true, - "dependencies": { - "asn1js": "^3.0.5", - "pvtsutils": "^1.3.5", - "tslib": "^2.6.2" - } - }, - "node_modules/@peculiar/json-schema": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.12.tgz", - "integrity": "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==", - "dev": true, - "dependencies": { - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@peculiar/webcrypto": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.5.tgz", - "integrity": "sha512-oDk93QCDGdxFRM8382Zdminzs44dg3M2+E5Np+JWkpqLDyJC9DviMh8F8mEJkYuUcUOGA5jHO5AJJ10MFWdbZw==", - "dev": true, - "dependencies": { - "@peculiar/asn1-schema": "^2.3.8", - "@peculiar/json-schema": "^1.1.12", - "pvtsutils": "^1.3.5", - "tslib": "^2.6.2", - "webcrypto-core": "^1.7.8" - }, - "engines": { - "node": ">=10.12.0" - } - }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -5984,6 +5948,27 @@ "node": ">=0.10.0" } }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "dev": true + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "dev": true + }, "node_modules/@sigstore/bundle": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.1.0.tgz", @@ -7482,34 +7467,6 @@ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, - "node_modules/@web-std/blob": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@web-std/blob/-/blob-3.0.5.tgz", - "integrity": "sha512-Lm03qr0eT3PoLBuhkvFBLf0EFkAsNz/G/AYCzpOdi483aFaVX86b4iQs0OHhzHJfN5C15q17UtDbyABjlzM96A==", - "dev": true, - "dependencies": { - "@web-std/stream": "1.0.0", - "web-encoding": "1.1.5" - } - }, - "node_modules/@web-std/file": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@web-std/file/-/file-3.0.3.tgz", - "integrity": "sha512-X7YYyvEERBbaDfJeC9lBKC5Q5lIEWYCP1SNftJNwNH/VbFhdHm+3neKOQP+kWEYJmosbDFq+NEUG7+XIvet/Jw==", - "dev": true, - "dependencies": { - "@web-std/blob": "^3.0.3" - } - }, - "node_modules/@web-std/stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@web-std/stream/-/stream-1.0.0.tgz", - "integrity": "sha512-jyIbdVl+0ZJyKGTV0Ohb9E6UnxP+t7ZzX4Do3AHjZKxUXKMs9EmqnBDQgHF7bEw0EzbQygOjtt/7gvtmi//iCQ==", - "dev": true, - "dependencies": { - "web-streams-polyfill": "^3.1.1" - } - }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -7563,13 +7520,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@zxing/text-encoding": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", - "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", - "dev": true, - "optional": true - }, "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -7969,20 +7919,6 @@ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, - "node_modules/asn1js": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", - "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", - "dev": true, - "dependencies": { - "pvtsutils": "^1.3.2", - "pvutils": "^1.1.3", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/async": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", @@ -8213,6 +8149,12 @@ "ieee754": "^1.1.13" } }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -8587,6 +8529,15 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, + "node_modules/check-more-types": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", + "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/child-process-promise": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/child-process-promise/-/child-process-promise-2.2.1.tgz", @@ -14901,6 +14852,19 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/joi": { + "version": "17.12.1", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.1.tgz", + "integrity": "sha512-vtxmq+Lsc5SlfqotnfVjlViWfOL9nt/avKNbKYizwf6gsCfq9NYY/ceYRMFD8XDdrjJ9abJyScWmhmIiy+XRtQ==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, "node_modules/jose": { "version": "4.15.4", "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.4.tgz", @@ -15373,6 +15337,15 @@ "url": "https://opencollective.com/node-fetch" } }, + "node_modules/lazy-ass": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", + "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", + "dev": true, + "engines": { + "node": "> 0.8" + } + }, "node_modules/lerna": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/lerna/-/lerna-7.4.2.tgz", @@ -18664,24 +18637,6 @@ } ] }, - "node_modules/pvtsutils": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.5.tgz", - "integrity": "sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA==", - "dev": true, - "dependencies": { - "tslib": "^2.6.1" - } - }, - "node_modules/pvutils": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz", - "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/qs": { "version": "6.11.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", @@ -20682,6 +20637,59 @@ "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", "dev": true }, + "node_modules/start-server-and-test": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-2.0.3.tgz", + "integrity": "sha512-QsVObjfjFZKJE6CS6bSKNwWZCKBG6975/jKRPPGFfFh+yOQglSeGXiNWjzgQNXdphcBI9nXbyso9tPfX4YAUhg==", + "dev": true, + "dependencies": { + "arg": "^5.0.2", + "bluebird": "3.7.2", + "check-more-types": "2.24.0", + "debug": "4.3.4", + "execa": "5.1.1", + "lazy-ass": "1.6.0", + "ps-tree": "1.2.0", + "wait-on": "7.2.0" + }, + "bin": { + "server-test": "src/bin/start.js", + "start-server-and-test": "src/bin/start.js", + "start-test": "src/bin/start.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/start-server-and-test/node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true + }, + "node_modules/start-server-and-test/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -22090,19 +22098,6 @@ "requires-port": "^1.0.0" } }, - "node_modules/util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -22235,6 +22230,25 @@ "node": ">=14" } }, + "node_modules/wait-on": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.2.0.tgz", + "integrity": "sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==", + "dev": true, + "dependencies": { + "axios": "^1.6.1", + "joi": "^17.11.0", + "lodash": "^4.17.21", + "minimist": "^1.2.8", + "rxjs": "^7.8.1" + }, + "bin": { + "wait-on": "bin/wait-on" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -22252,23 +22266,13 @@ "defaults": "^1.0.3" } }, - "node_modules/web-encoding": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz", - "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==", - "dev": true, - "dependencies": { - "util": "^0.12.3" - }, - "optionalDependencies": { - "@zxing/text-encoding": "0.9.0" - } - }, "node_modules/web-streams-polyfill": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.2.tgz", "integrity": "sha512-3pRGuxRF5gpuZc0W+EpwQRmCD7gRqcDOMt688KmdlDAgAyaB1XlN0zq2njfDNm44XVdIouE7pZ6GzbdyH47uIQ==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">= 8" } @@ -22279,19 +22283,6 @@ "integrity": "sha512-LCHW+fE2UBJ2vjhqJujqmoxh1ytEDEr0dPO3CabMdMDJPKmsaxzS90V1Ar6LtNE5VHLqxR4YMEj1i4lzMAccIA==", "dev": true }, - "node_modules/webcrypto-core": { - "version": "1.7.8", - "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.8.tgz", - "integrity": "sha512-eBR98r9nQXTqXt/yDRtInszPMjTaSAMJAFDg2AHsgrnczawT1asx9YNBX6k5p+MekbPF4+s/UJJrr88zsTqkSg==", - "dev": true, - "dependencies": { - "@peculiar/asn1-schema": "^2.3.8", - "@peculiar/json-schema": "^1.1.12", - "asn1js": "^3.0.1", - "pvtsutils": "^1.3.5", - "tslib": "^2.6.2" - } - }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -24613,14 +24604,14 @@ "cross-fetch": "^3.1.6" }, "devDependencies": { - "@inrupt/jest-jsdom-polyfills": "^3.0.2", "@ldo/rdf-utils": "^0.0.1-alpha.17", "@rdfjs/types": "^1.0.1", - "@solid/community-server": "^6.0.2", "@testing-library/react": "^14.1.2", "@types/jest": "^29.0.3", "jest-environment-jsdom": "^29.7.0", - "ts-jest": "^29.0.2" + "start-server-and-test": "^2.0.3", + "ts-jest": "^29.1.2", + "ts-node": "^10.9.2" } }, "packages/solid-react/node_modules/@jest/console": { diff --git a/packages/solid-react/jest.config.js b/packages/solid-react/jest.config.js index 5850b72..4275a3f 100644 --- a/packages/solid-react/jest.config.js +++ b/packages/solid-react/jest.config.js @@ -2,4 +2,5 @@ const sharedConfig = require("../../jest.config.js"); module.exports = { ...sharedConfig, rootDir: "./", + testEnvironment: "jsdom", }; diff --git a/packages/solid-react/package.json b/packages/solid-react/package.json index 5014a9c..d20dfd7 100644 --- a/packages/solid-react/package.json +++ b/packages/solid-react/package.json @@ -6,11 +6,14 @@ "scripts": { "build": "tsc --project tsconfig.build.json", "watch": "tsc --watch", - "test": "jest --coverage", + "test": "npm run test:integration", "test:watch": "jest --watch", "prepublishOnly": "npm run test && npm run build", "build:ldo": "ldo build --input src/shapes --output src/ldo", - "lint": "eslint src/** --fix --no-error-on-unmatched-pattern" + "lint": "eslint src/** --fix --no-error-on-unmatched-pattern", + "test:integration": "start-server-and-test start-test-server http://localhost:3001 start-integration-test", + "start-test-server": "ts-node ./test/test-server/runServer.ts", + "start-integration-test": "jest --coverage" }, "repository": { "type": "git", @@ -28,7 +31,9 @@ "@testing-library/react": "^14.1.2", "@types/jest": "^29.0.3", "jest-environment-jsdom": "^29.7.0", - "ts-jest": "^29.0.2" + "start-server-and-test": "^2.0.3", + "ts-jest": "^29.1.2", + "ts-node": "^10.9.2" }, "dependencies": { "@inrupt/solid-client": "^2.0.0", diff --git a/packages/solid-react/src/UnauthenticatedSolidLdoProvider.tsx b/packages/solid-react/src/UnauthenticatedSolidLdoProvider.tsx new file mode 100644 index 0000000..3ff6f99 --- /dev/null +++ b/packages/solid-react/src/UnauthenticatedSolidLdoProvider.tsx @@ -0,0 +1,61 @@ +import React, { useCallback, useMemo } from "react"; +import type { FunctionComponent, PropsWithChildren } from "react"; +import type { LoginOptions, SessionInfo } from "./SolidAuthContext"; +import { SolidAuthContext } from "./SolidAuthContext"; +import libraryFetch from "cross-fetch"; +import { SolidLdoProvider } from "./SolidLdoProvider"; + +const DUMMY_SESSION: SessionInfo = { + isLoggedIn: false, + webId: undefined, + clientAppId: undefined, + sessionId: "no_session", + expirationDate: undefined, +}; + +export const UnauthenticatedSolidLdoProvider: FunctionComponent< + PropsWithChildren +> = ({ children }) => { + const login = useCallback( + async (_issuer: string, _options?: LoginOptions) => { + throw new Error( + "login is not available for a UnauthenticatedSolidLdoProvider", + ); + }, + [], + ); + + const logout = useCallback(async () => { + throw new Error( + "logout is not available for a UnauthenticatedSolidLdoProvider", + ); + }, []); + + const signUp = useCallback( + async (_issuer: string, _options?: LoginOptions) => { + throw new Error( + "signUp is not available for a UnauthenticatedSolidLdoProvider", + ); + }, + [], + ); + + const solidAuthFunctions = useMemo( + () => ({ + runInitialAuthCheck: () => {}, + login, + logout, + signUp, + session: DUMMY_SESSION, + ranInitialAuthCheck: true, + fetch: libraryFetch, + }), + [login, logout, signUp], + ); + + return ( + + {children} + + ); +}; diff --git a/packages/solid-react/src/index.ts b/packages/solid-react/src/index.ts index 2d354c5..85c0a69 100644 --- a/packages/solid-react/src/index.ts +++ b/packages/solid-react/src/index.ts @@ -1,4 +1,5 @@ export * from "./BrowserSolidLdoProvider"; +export * from "./UnauthenticatedSolidLdoProvider"; export * from "./SolidAuthContext"; export { useLdo } from "./SolidLdoProvider"; diff --git a/packages/solid-react/test/BrowserAuthentication.test.tsx b/packages/solid-react/test/BrowserAuthentication.test.tsx deleted file mode 100644 index 9ce9f93..0000000 --- a/packages/solid-react/test/BrowserAuthentication.test.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from "react"; -import type { FunctionComponent } from "react"; -import { fireEvent, render, screen } from "@testing-library/react"; -import { setUpServer } from "./setUpServer"; -import { useSolidAuth } from "../src/SolidAuthContext"; -import { ROOT_CONTAINER } from "./solidServer.helper"; - -describe("Browser Authentication", () => { - const s = setUpServer(); - - const AuthTest: FunctionComponent = () => { - const { login, session, logout } = useSolidAuth(); - - return ( -
-
{JSON.stringify(session)}
- - -
- ); - }; - - it("properly logs in", async () => { - console.log("b"); - expect(true).toBe(true); - // render( - // - // - // , - // ); - // const loginButton = screen.getByRole("button", { name: "logout" }); - // fireEvent.click(loginButton); - // await screen.findByText("Log in"); - // expect(window.location.pathname).toBe("/.account/login/password/"); - // // const authorizeButton = screen.getByText("Log in"); - // // const emailBox = screen.getById - }); -}); diff --git a/packages/solid-react/test/Integration.test.tsx b/packages/solid-react/test/Integration.test.tsx new file mode 100644 index 0000000..188f0d0 --- /dev/null +++ b/packages/solid-react/test/Integration.test.tsx @@ -0,0 +1,36 @@ +import React from "react"; +import type { FunctionComponent } from "react"; +import { render, screen } from "@testing-library/react"; +import { SAMPLE_DATA_URI, setUpServer } from "./setUpServer"; +import { UnauthenticatedSolidLdoProvider } from "../src/UnauthenticatedSolidLdoProvider"; +import { useResource } from "../src/useResource"; + +// Use an increased timeout, since the CSS server takes too much setup time. +jest.setTimeout(40_000); + +describe("Integration Tests", () => { + setUpServer(); + + /** + * =========================================================================== + * useResource + * =========================================================================== + */ + describe("useResource", () => { + it("Fetches a resource and indicates it is loading while doing so", async () => { + const UseResourceTest: FunctionComponent = () => { + const resource = useResource(SAMPLE_DATA_URI); + if (resource?.isLoading()) return

Loading

; + return

{resource.status.type}

; + }; + render( + + + , + ); + await screen.findByText("Loading"); + const resourceStatus = await screen.findByRole("status"); + expect(resourceStatus.innerHTML).toBe("dataReadSuccess"); + }); + }); +}); diff --git a/packages/solid-react/test/setUpServer.ts b/packages/solid-react/test/setUpServer.ts index 3048e72..a669c01 100644 --- a/packages/solid-react/test/setUpServer.ts +++ b/packages/solid-react/test/setUpServer.ts @@ -1,8 +1,9 @@ import type { ContainerUri, LeafUri } from "@ldo/solid"; -import { ROOT_CONTAINER, createApp } from "./solidServer.helper"; -import type { App } from "@solid/community-server"; import fetch from "cross-fetch"; +export const SERVER_DOMAIN = process.env.SERVER || "http://localhost:3001/"; +export const ROOT_ROUTE = process.env.ROOT_CONTAINER || "example/"; +export const ROOT_CONTAINER = `${SERVER_DOMAIN}${ROOT_ROUTE}`; export const TEST_CONTAINER_SLUG = "test_ldo/"; export const TEST_CONTAINER_URI = `${ROOT_CONTAINER}${TEST_CONTAINER_SLUG}` as ContainerUri; @@ -51,7 +52,6 @@ export const TEST_CONTAINER_TTL = `@prefix dc: . posix:size 10.`; export interface SetUpServerReturn { - app: App; authFetch: typeof fetch; fetchMock: jest.Mock< Promise, @@ -66,28 +66,21 @@ export function setUpServer(): SetUpServerReturn { const s: SetUpServerReturn = {}; beforeAll(async () => { - // Start up the server - s.app = await createApp(); - await s.app.start(); - // s.authFetch = await getAuthenticatedFetch(); s.authFetch = fetch; }); - afterAll(async () => { - s.app.stop(); - }); - beforeEach(async () => { s.fetchMock = jest.fn(s.authFetch); // Create a new document called sample.ttl - await s.authFetch(ROOT_CONTAINER, { + const result = await s.authFetch(ROOT_CONTAINER, { method: "POST", headers: { link: '; rel="type"', slug: TEST_CONTAINER_SLUG, }, }); + console.log("Created container", result.status); await Promise.all([ s.authFetch(TEST_CONTAINER_URI, { method: "POST", diff --git a/packages/solid-react/test/solidServer.helper.ts b/packages/solid-react/test/solidServer.helper.ts deleted file mode 100644 index e29874a..0000000 --- a/packages/solid-react/test/solidServer.helper.ts +++ /dev/null @@ -1,122 +0,0 @@ -// Taken from https://github.com/comunica/comunica/blob/b237be4265c353a62a876187d9e21e3bc05123a3/engines/query-sparql/test/QuerySparql-solid-test.ts#L9 - -import * as path from "path"; -import type { KeyPair } from "@inrupt/solid-client-authn-core"; -import { - buildAuthenticatedFetch, - createDpopHeader, - generateDpopKeyPair, -} from "@inrupt/solid-client-authn-core"; -import type { App } from "@solid/community-server"; -import { AppRunner, resolveModulePath } from "@solid/community-server"; -import "jest-rdf"; -import fetch from "cross-fetch"; - -const config = [ - { - podName: process.env.USER_NAME || "example", - email: process.env.EMAIL || "hello@example.com", - password: process.env.PASSWORD || "abc123", - }, -]; - -export const SERVER_DOMAIN = process.env.SERVER || "http://localhost:3001/"; -export const ROOT_ROUTE = process.env.ROOT_CONTAINER || "example/"; -export const ROOT_CONTAINER = `${SERVER_DOMAIN}${ROOT_ROUTE}`; - -// Use an increased timeout, since the CSS server takes too much setup time. -jest.setTimeout(40_000); - -export async function createApp(): Promise { - if (process.env.SERVER) { - return { - start: () => {}, - stop: () => {}, - } as App; - } - const appRunner = new AppRunner(); - return appRunner.create( - { - mainModulePath: resolveModulePath(""), - typeChecking: false, - }, - resolveModulePath("config/default.json"), - {}, - { - port: 3_001, - loggingLevel: "off", - seededPodConfigJson: path.join( - __dirname, - "configs", - "solid-css-seed.json", - ), - }, - ); -} - -export interface ISecretData { - id: string; - secret: string; -} - -// From https://communitysolidserver.github.io/CommunitySolidServer/5.x/usage/client-credentials/ -export async function getSecret(): Promise { - const result = await fetch(`${SERVER_DOMAIN}idp/credentials/`, { - method: "POST", - headers: { "content-type": "application/json" }, - body: JSON.stringify({ - email: config[0].email, - password: config[0].password, - name: config[0].podName, - }), - }); - const json = await result.json(); - return json; -} - -export interface ITokenData { - accessToken: string; - dpopKey: KeyPair; -} - -// From https://communitysolidserver.github.io/CommunitySolidServer/5.x/usage/client-credentials/ -export async function refreshToken({ - id, - secret, -}: ISecretData): Promise { - const dpopKey = await generateDpopKeyPair(); - const authString = `${encodeURIComponent(id)}:${encodeURIComponent(secret)}`; - const tokenUrl = `${SERVER_DOMAIN}.oidc/token`; - const accessToken = await fetch(tokenUrl, { - method: "POST", - headers: { - // The header needs to be in base64 encoding. - authorization: `Basic ${Buffer.from(authString).toString("base64")}`, - "content-type": "application/x-www-form-urlencoded", - dpop: await createDpopHeader(tokenUrl, "POST", dpopKey), - }, - body: "grant_type=client_credentials&scope=webid", - }) - .then((res) => res.json()) - .then((res) => res.access_token); - - return { accessToken, dpopKey }; -} - -// export async function getAuthenticatedFetch() { -// // Generate secret -// const secret = await getSecret(); - -// if (!secret) throw new Error("No Secret"); - -// // Get token -// const token = await refreshToken(secret); - -// if (!token) throw new Error("No Token"); - -// // Build authenticated fetch -// const authFetch = await buildAuthenticatedFetch(token.accessToken, { -// dpopKey: token.dpopKey, -// }); -// return authFetch; -// } diff --git a/packages/solid-react/test/test-server/configs/components-config/unauthenticatedServer.json b/packages/solid-react/test/test-server/configs/components-config/unauthenticatedServer.json new file mode 100644 index 0000000..56b2a2f --- /dev/null +++ b/packages/solid-react/test/test-server/configs/components-config/unauthenticatedServer.json @@ -0,0 +1,52 @@ +{ + "@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^6.0.0/components/context.jsonld", + "import": [ + "css:config/app/main/default.json", + "css:config/app/init/initialize-prefilled-root.json", + "css:config/app/setup/optional.json", + "css:config/app/variables/default.json", + "css:config/http/handler/default.json", + "css:config/http/middleware/default.json", + "css:config/http/notifications/all.json", + "css:config/http/server-factory/http.json", + "css:config/http/static/default.json", + "css:config/identity/access/public.json", + "css:config/identity/email/default.json", + "css:config/identity/handler/default.json", + "css:config/identity/ownership/token.json", + "css:config/identity/pod/static.json", + "css:config/identity/registration/enabled.json", + "css:config/ldp/authentication/dpop-bearer.json", + "css:config/ldp/authorization/webacl.json", + "css:config/ldp/handler/default.json", + "css:config/ldp/metadata-parser/default.json", + "css:config/ldp/metadata-writer/default.json", + "css:config/ldp/modes/default.json", + "css:config/storage/backend/memory.json", + "css:config/storage/key-value/resource-store.json", + "css:config/storage/middleware/default.json", + "css:config/util/auxiliary/acl.json", + "css:config/util/identifiers/suffix.json", + "css:config/util/index/default.json", + "css:config/util/logging/winston.json", + "css:config/util/representation-conversion/default.json", + "css:config/util/resource-locker/memory.json", + "css:config/util/variables/default.json" + ], + "@graph": [ + { + "comment": "A Solid server that stores its resources in memory and uses WAC for authorization." + }, + { + "comment": "The location of the new pod templates folder.", + "@type": "Override", + "overrideInstance": { + "@id": "urn:solid-server:default:PodResourcesGenerator" + }, + "overrideParameters": { + "@type": "StaticFolderGenerator", + "templateFolder": "./test/test-server/configs/template" + } + } + ] +} diff --git a/packages/solid-react/test/configs/solid-css-seed.json b/packages/solid-react/test/test-server/configs/solid-css-seed.json similarity index 55% rename from packages/solid-react/test/configs/solid-css-seed.json rename to packages/solid-react/test/test-server/configs/solid-css-seed.json index 1b10b4c..0b139ea 100644 --- a/packages/solid-react/test/configs/solid-css-seed.json +++ b/packages/solid-react/test/test-server/configs/solid-css-seed.json @@ -2,6 +2,7 @@ { "podName": "example", "email": "hello@example.com", - "password": "abc123" + "password": "abc123", + "template": "./template" } ] \ No newline at end of file diff --git a/packages/solid-react/test/test-server/configs/template/wac/.acl.hbs b/packages/solid-react/test/test-server/configs/template/wac/.acl.hbs new file mode 100644 index 0000000..48fd101 --- /dev/null +++ b/packages/solid-react/test/test-server/configs/template/wac/.acl.hbs @@ -0,0 +1,13 @@ +@prefix : <#>. +@prefix acl: . +@prefix foaf: . +@prefix eve: <./>. +@prefix c: <./profile/card#>. + +:ControlReadWrite + a acl:Authorization; + acl:accessTo eve:; + acl:agent c:me, ; + acl:agentClass foaf:Agent; + acl:default eve:; + acl:mode acl:Control, acl:Read, acl:Write. \ No newline at end of file diff --git a/packages/solid-react/test/test-server/configs/template/wac/profile/card.acl.hbs b/packages/solid-react/test/test-server/configs/template/wac/profile/card.acl.hbs new file mode 100644 index 0000000..ea7c2a8 --- /dev/null +++ b/packages/solid-react/test/test-server/configs/template/wac/profile/card.acl.hbs @@ -0,0 +1,19 @@ +# ACL resource for the WebID profile document +@prefix acl: . +@prefix foaf: . + +# The WebID profile is readable by the public. +# This is required for discovery and verification, +# e.g. when checking identity providers. +<#public> + a acl:Authorization; + acl:agentClass foaf:Agent; + acl:accessTo <./card>; + acl:mode acl:Read. + +# The owner has full access to the profile +<#owner> + a acl:Authorization; + acl:agent <{{webId}}>; + acl:accessTo <./card>; + acl:mode acl:Read, acl:Write, acl:Control. \ No newline at end of file diff --git a/packages/solid-react/test/test-server/runServer.ts b/packages/solid-react/test/test-server/runServer.ts new file mode 100644 index 0000000..9d91222 --- /dev/null +++ b/packages/solid-react/test/test-server/runServer.ts @@ -0,0 +1,7 @@ +import { createApp } from "./solidServer.helper"; + +async function run() { + const app = await createApp(); + await app.start(); +} +run(); diff --git a/packages/solid-react/test/test-server/solidServer.helper.ts b/packages/solid-react/test/test-server/solidServer.helper.ts new file mode 100644 index 0000000..3cc66cf --- /dev/null +++ b/packages/solid-react/test/test-server/solidServer.helper.ts @@ -0,0 +1,42 @@ +// Taken from https://github.com/comunica/comunica/blob/b237be4265c353a62a876187d9e21e3bc05123a3/engines/query-sparql/test/QuerySparql-solid-test.ts#L9 + +import * as path from "path"; +import type { App } from "@solid/community-server"; +import { AppRunner, resolveModulePath } from "@solid/community-server"; + +export async function createApp(): Promise { + if (process.env.SERVER) { + return { + start: () => {}, + stop: () => {}, + } as App; + } + const appRunner = new AppRunner(); + return appRunner.create( + { + mainModulePath: resolveModulePath(""), + typeChecking: false, + }, + path.join( + __dirname, + "configs", + "components-config", + "unauthenticatedServer.json", + ), + {}, + { + port: 3_001, + loggingLevel: "off", + seededPodConfigJson: path.join( + __dirname, + "configs", + "solid-css-seed.json", + ), + }, + ); +} + +export interface ISecretData { + id: string; + secret: string; +}