diff --git a/config/app/init/base/init.json b/config/app/init/base/init.json index b19126bd6..f3fad40d1 100644 --- a/config/app/init/base/init.json +++ b/config/app/init/base/init.json @@ -3,7 +3,8 @@ "import": [ "files-scs:config/app/init/initializers/base-url.json", "files-scs:config/app/init/initializers/logger.json", - "files-scs:config/app/init/initializers/server.json" + "files-scs:config/app/init/initializers/server.json", + "files-scs:config/app/init/initializers/version.json" ], "@graph": [ { @@ -14,7 +15,8 @@ { "@id": "urn:solid-server:default:LoggerInitializer" }, { "@id": "urn:solid-server:default:BaseUrlVerifier" }, { "@id": "urn:solid-server:default:ParallelInitializer" }, - { "@id": "urn:solid-server:default:ServerInitializer" } + { "@id": "urn:solid-server:default:ServerInitializer" }, + { "@id": "urn:solid-server:default:ModuleVersionVerifier" } ] } ] diff --git a/config/app/init/initializers/version.json b/config/app/init/initializers/version.json new file mode 100644 index 000000000..ad06d3d1f --- /dev/null +++ b/config/app/init/initializers/version.json @@ -0,0 +1,12 @@ +{ + "@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^2.0.0/components/context.jsonld", + "@graph": [ + { + "comment": "Logs a warning if the base URL changes.", + "@id": "urn:solid-server:default:ModuleVersionVerifier", + "@type": "ModuleVersionVerifier", + "storageKey": "current-server-version", + "storage": { "@id": "urn:solid-server:default:SetupStorage" } + } + ] +} diff --git a/package-lock.json b/package-lock.json index 34e7d8db0..7c54daae0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@types/bcrypt": "^5.0.0", "@types/cors": "^2.8.12", "@types/end-of-stream": "^1.4.1", + "@types/fs-extra": "^9.0.13", "@types/lodash.orderby": "^4.6.6", "@types/marked": "^4.0.2", "@types/mime-types": "^2.1.1", @@ -42,6 +43,7 @@ "end-of-stream": "^1.4.4", "escape-string-regexp": "^4.0.0", "fetch-sparql-endpoint": "^2.4.0", + "fs-extra": "^10.0.0", "handlebars": "^4.7.7", "jose": "^4.4.0", "lodash.orderby": "^4.6.0", @@ -76,7 +78,6 @@ "@tsconfig/node12": "^1.0.9", "@types/cheerio": "^0.22.30", "@types/ejs": "^3.1.0", - "@types/fs-extra": "^9.0.13", "@types/jest": "^27.4.0", "@types/set-cookie-parser": "^2.4.2", "@types/supertest": "^2.0.11", @@ -91,7 +92,6 @@ "eslint-plugin-jest": "^26.0.0", "eslint-plugin-tsdoc": "^0.2.14", "eslint-plugin-unused-imports": "^2.0.0", - "fs-extra": "^10.0.0", "husky": "^4.3.8", "jest": "^27.4.7", "jest-rdf": "^1.7.0", @@ -4430,7 +4430,6 @@ "version": "9.0.13", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", - "dev": true, "dependencies": { "@types/node": "*" } @@ -8310,7 +8309,6 @@ "version": "10.0.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", - "dev": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -8324,7 +8322,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, "engines": { "node": ">= 10.0.0" } @@ -8907,8 +8904,7 @@ "node_modules/graceful-fs": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" }, "node_modules/graphql": { "version": "15.8.0", @@ -10858,7 +10854,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, "dependencies": { "universalify": "^2.0.0" }, @@ -10870,7 +10865,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, "engines": { "node": ">= 10.0.0" } @@ -18559,7 +18553,6 @@ "version": "9.0.13", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", - "dev": true, "requires": { "@types/node": "*" } @@ -21542,7 +21535,6 @@ "version": "10.0.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", - "dev": true, "requires": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -21552,8 +21544,7 @@ "universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" } } }, @@ -21986,8 +21977,7 @@ "graceful-fs": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" }, "graphql": { "version": "15.8.0", @@ -23445,7 +23435,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, "requires": { "graceful-fs": "^4.1.6", "universalify": "^2.0.0" @@ -23454,8 +23443,7 @@ "universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" } } }, diff --git a/package.json b/package.json index 814bbc0ce..9f0cfa30c 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "@types/bcrypt": "^5.0.0", "@types/cors": "^2.8.12", "@types/end-of-stream": "^1.4.1", + "@types/fs-extra": "^9.0.13", "@types/lodash.orderby": "^4.6.6", "@types/marked": "^4.0.2", "@types/mime-types": "^2.1.1", @@ -108,6 +109,7 @@ "end-of-stream": "^1.4.4", "escape-string-regexp": "^4.0.0", "fetch-sparql-endpoint": "^2.4.0", + "fs-extra": "^10.0.0", "handlebars": "^4.7.7", "jose": "^4.4.0", "lodash.orderby": "^4.6.0", @@ -139,7 +141,6 @@ "@tsconfig/node12": "^1.0.9", "@types/cheerio": "^0.22.30", "@types/ejs": "^3.1.0", - "@types/fs-extra": "^9.0.13", "@types/jest": "^27.4.0", "@types/set-cookie-parser": "^2.4.2", "@types/supertest": "^2.0.11", @@ -154,7 +155,6 @@ "eslint-plugin-jest": "^26.0.0", "eslint-plugin-tsdoc": "^0.2.14", "eslint-plugin-unused-imports": "^2.0.0", - "fs-extra": "^10.0.0", "husky": "^4.3.8", "jest": "^27.4.7", "jest-rdf": "^1.7.0", diff --git a/src/index.ts b/src/index.ts index 899275ed8..86f2cf068 100644 --- a/src/index.ts +++ b/src/index.ts @@ -208,6 +208,7 @@ export * from './init/ContainerInitializer'; export * from './init/Initializer'; export * from './init/LoggerInitializer'; export * from './init/ServerInitializer'; +export * from './init/ModuleVersionVerifier'; // Logging export * from './logging/LazyLogger'; diff --git a/src/init/ModuleVersionVerifier.ts b/src/init/ModuleVersionVerifier.ts new file mode 100644 index 000000000..37039efd7 --- /dev/null +++ b/src/init/ModuleVersionVerifier.ts @@ -0,0 +1,30 @@ +import { readJson } from 'fs-extra'; +import type { KeyValueStorage } from '../storage/keyvalue/KeyValueStorage'; +import { modulePathPlaceholder, resolveAssetPath } from '../util/PathUtil'; +import { Initializer } from './Initializer'; + +const PACKAGE_JSON_PATH = `${modulePathPlaceholder}package.json`; + +/** + * This initializer simply writes the version number of the server to the storage. + * This will be relevant in the future when we look into migration initializers. + * + * It automatically parses the version number from the `package.json`. + */ +export class ModuleVersionVerifier extends Initializer { + private readonly storageKey: string; + private readonly storage: KeyValueStorage; + + public constructor(storageKey: string, storage: KeyValueStorage) { + super(); + this.storageKey = storageKey; + this.storage = storage; + } + + public async handle(): Promise { + const path = resolveAssetPath(PACKAGE_JSON_PATH); + const pkg = await readJson(path); + + await this.storage.set(this.storageKey, pkg.version); + } +} diff --git a/test/unit/init/ModuleVersionVerifier.test.ts b/test/unit/init/ModuleVersionVerifier.test.ts new file mode 100644 index 000000000..f524c0340 --- /dev/null +++ b/test/unit/init/ModuleVersionVerifier.test.ts @@ -0,0 +1,17 @@ +import { ModuleVersionVerifier } from '../../../src/init/ModuleVersionVerifier'; + +describe('A ModuleVersionVerifier', (): void => { + const storageKey = 'uniqueVersionKey'; + let storageMap: Map; + let initializer: ModuleVersionVerifier; + + beforeEach(async(): Promise => { + storageMap = new Map(); + initializer = new ModuleVersionVerifier(storageKey, storageMap as any); + }); + + it('stores the latest version.', async(): Promise => { + await expect(initializer.handle()).resolves.toBeUndefined(); + expect(storageMap.get(storageKey)).toMatch(/^\d+\.\d+\.\d+(?:-.+)?/u); + }); +});