diff --git a/src/Prelude.ts b/src/Prelude.ts index 73a0b94..aa76a5c 100644 --- a/src/Prelude.ts +++ b/src/Prelude.ts @@ -1,13 +1,31 @@ import ApiClient from "@prelude-music/ts-client"; import {Page, Artist, Album, Track} from "./index.js"; +import {Version} from "./Version.js"; +import {ServerInfo} from "./ServerInfo.js"; /** * Prelude SDK */ -export class Prelude { +export class Prelude implements Version.Versionable { + /** + * The API version this SDK is compatible with + */ + public static readonly VERSION = Version.from("0.0.0"); + /** + * The API version this SDK is compatible with + */ + public readonly version = Prelude.VERSION; + /** @internal **/ public readonly api: ApiClient; + /** + * API server info + */ + public async info() { + return new ServerInfo(Version.from((await this.api.info()).body.prelude.version)); + } + /** * Artists */ diff --git a/src/ServerInfo.ts b/src/ServerInfo.ts new file mode 100644 index 0000000..544d209 --- /dev/null +++ b/src/ServerInfo.ts @@ -0,0 +1,6 @@ +import {Version} from "./Version.js"; + +export class ServerInfo implements Version.Versionable{ + public constructor(public readonly version: Version) { + } +} diff --git a/src/Version.ts b/src/Version.ts new file mode 100644 index 0000000..f719915 --- /dev/null +++ b/src/Version.ts @@ -0,0 +1,74 @@ +class Version { + public constructor( + public readonly major: number, + public readonly minor: number, + public readonly patch: number, + public readonly label?: string + ) { + } + + public static from(version: `${number}.${number}.${number}${`-${string}` | ""}`) { + const parts = version.split("."); + if (parts.length > 3 || parts.length <= 1) throw new TypeError(`Invalid version string: ${version}`); + const major = Number.parseInt(parts[0]!, 10); + const minor = parts[1] === undefined ? 0 : Number.parseInt(parts[1], 10); + let label: string | undefined; + let patch: number; + if (parts[2] !== undefined) { + const dashIndex = parts[2].indexOf("-"); + if (dashIndex === -1) + patch = Number.parseInt(parts[2], 10); + else { + patch = Number.parseInt(parts[2].slice(0, dashIndex), 10); + label = parts[2].slice(dashIndex + 1); + } + } + else patch = 0; + return new Version(major, minor, patch, label); + } + + public toString() { + return `${this.major}.${this.minor}.${this.patch}${this.label === undefined ? "" : `-${this.label}`}`; + } + + /** + * Check whether this version (local) is compatible with the given version (remote) + * + * ``` + * local major != remote major => false + * local minor > remote minor => false + * otherwise => true + * ``` + * + * @param version + */ + public isCompatible(version: Version): boolean; + /** + * Check whether the current version (local) is compatible with the version of the given object (remote) + * + * ``` + * local major != remote major => false + * local minor > remote minor => false + * otherwise => true + * ``` + * + * @param versionable + */ + public isCompatible(versionable: Version.Versionable): boolean; + /** + * @internal + */ + public isCompatible(a: Version | Version.Versionable): boolean { + const version = a instanceof Version ? a : a.version; + if (this.major !== version.major) return false; + return this.minor >= version.minor; + } +} + +namespace Version { + export interface Versionable { + version: Version; + } +} + +export {Version};