UNPKG

@lucidcms/core

Version:

The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.

1 lines 6.63 kB
{"version":3,"file":"update-available.mjs","names":["packageJson.name","packageJson.version"],"sources":["../../../../src/libs/cli/services/update-available.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport boxen from \"boxen\";\nimport picocolors from \"picocolors\";\nimport semver from \"semver\";\nimport packageJson from \"../../../../package.json\" with { type: \"json\" };\nimport { ensureLucidDirectoryExists } from \"../../../utils/helpers/lucid-directory.js\";\n\nconst UPDATE_AVAILABLE_FILE = \"update-available.json\";\nconst ONE_DAY_MS = 24 * 60 * 60 * 1000;\n\ntype UpdateCache = {\n\tcheckedAt: number;\n\tlatestVersion: string | null;\n\tcurrentVersion: string;\n};\n\ntype CoreUpdateAvailable = {\n\tavailable: boolean;\n\tshow: boolean;\n\tlatestVersion: string | null;\n\tcurrentVersion: string;\n\trenderUpdateBox: () => void;\n};\n\nconst parseCache = async (filePath: string): Promise<UpdateCache | null> => {\n\tif (!existsSync(filePath)) {\n\t\treturn null;\n\t}\n\ttry {\n\t\tconst raw = await readFile(filePath, \"utf-8\");\n\t\tconst parsed = JSON.parse(raw);\n\t\tconst checkedAt =\n\t\t\ttypeof parsed.checkedAt === \"number\" ? parsed.checkedAt : null;\n\t\tconst latestVersion =\n\t\t\ttypeof parsed.latestVersion === \"string\" || parsed.latestVersion === null\n\t\t\t\t? parsed.latestVersion\n\t\t\t\t: null;\n\t\tconst currentVersion =\n\t\t\ttypeof parsed.currentVersion === \"string\" ? parsed.currentVersion : null;\n\n\t\tif (checkedAt === null || currentVersion === null) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn {\n\t\t\tcheckedAt,\n\t\t\tlatestVersion,\n\t\t\tcurrentVersion,\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n};\n\nconst writeCache = async (filePath: string, data: UpdateCache) => {\n\tawait writeFile(filePath, JSON.stringify(data, null, 2), \"utf-8\");\n};\n\n/**\n * Gets the latest version of a package from the npm registry\n */\nconst getLatestVersion = async (packageName: string) => {\n\ttry {\n\t\tconst response = await fetch(\n\t\t\t`https://registry.npmjs.org/${packageName}/latest`,\n\t\t);\n\t\tconst data = await response.json();\n\t\treturn data.version as string;\n\t} catch {\n\t\treturn null;\n\t}\n};\n\n/**\n * Renders a box with the update information\n */\nconst renderUpdateBox = (\n\tupdateAvailable: Omit<CoreUpdateAvailable, \"renderUpdateBox\">,\n) => {\n\tif (!updateAvailable.show || !updateAvailable.available) {\n\t\treturn;\n\t}\n\n\tconst { currentVersion, latestVersion } = updateAvailable;\n\n\tconst versionLines = [\n\t\t`Current: ${picocolors.yellow(currentVersion)}`,\n\t\t`Latest: ${picocolors.green(latestVersion ?? \"unknown\")}`,\n\t];\n\n\tconst updateCommand = picocolors.cyan(\n\t\t`npm install ${packageJson.name}@latest`,\n\t);\n\n\tconst lines = [\n\t\t\"A new version of Lucid CMS is available!\",\n\t\t\"\",\n\t\t...versionLines,\n\t\t\"\",\n\t\t`Run ${updateCommand} to update`,\n\t\t\"\",\n\t\tpicocolors.dim(\"View the changelog: \") +\n\t\t\tpicocolors.cyan(\"https://github.com/buildlucid/lucid-cms/releases\"),\n\t\tpicocolors.dim(\n\t\t\t\"Remember to back up your database before updating or running migrations.\",\n\t\t),\n\t];\n\n\tconst box = boxen(lines.join(\"\\n\"), {\n\t\tpadding: 1,\n\t\tmargin: 1,\n\t\tborderStyle: \"round\",\n\t\tborderColor: \"yellow\",\n\t\ttitle: \"Update Available\",\n\t\ttitleAlignment: \"left\",\n\t});\n\n\tconsole.log(box);\n};\n\n/**\n * Checks if an update is available for the core package\n *\n * - Will only check once per day\n * - Invalidates cache if current version changes\n */\nconst updateAvailable = async (): Promise<CoreUpdateAvailable> => {\n\tconst lucidDir = await ensureLucidDirectoryExists();\n\tconst cachePath = join(lucidDir, UPDATE_AVAILABLE_FILE);\n\tconst cache = await parseCache(cachePath);\n\tconst now = Date.now();\n\tconst currentVersion = packageJson.version;\n\n\tconst versionChanged = cache ? cache.currentVersion !== currentVersion : true;\n\tconst isCacheFresh = cache\n\t\t? now - cache.checkedAt < ONE_DAY_MS && !versionChanged\n\t\t: false;\n\n\tlet latestVersion = isCacheFresh ? (cache?.latestVersion ?? null) : null;\n\n\tif (!isCacheFresh) {\n\t\tlatestVersion = await getLatestVersion(packageJson.name);\n\t\tawait writeCache(cachePath, {\n\t\t\tcheckedAt: now,\n\t\t\tlatestVersion,\n\t\t\tcurrentVersion,\n\t\t});\n\t}\n\n\tconst updateAvailableFlag =\n\t\tlatestVersion && semver.valid(latestVersion) && semver.valid(currentVersion)\n\t\t\t? semver.gt(latestVersion, currentVersion)\n\t\t\t: false;\n\n\treturn {\n\t\tavailable: updateAvailableFlag,\n\t\tshow: !isCacheFresh && updateAvailableFlag,\n\t\tlatestVersion,\n\t\tcurrentVersion,\n\t\trenderUpdateBox: () =>\n\t\t\trenderUpdateBox({\n\t\t\t\tavailable: updateAvailableFlag,\n\t\t\t\tshow: !isCacheFresh && updateAvailableFlag,\n\t\t\t\tlatestVersion,\n\t\t\t\tcurrentVersion,\n\t\t\t}),\n\t};\n};\n\nexport default updateAvailable;\n"],"mappings":"qWASA,MAiBM,EAAa,KAAO,IAAkD,CAC3E,GAAI,CAAC,EAAW,CAAQ,EACvB,OAAO,KAER,GAAI,CACH,IAAM,EAAM,MAAM,EAAS,EAAU,OAAO,EACtC,EAAS,KAAK,MAAM,CAAG,EACvB,EACL,OAAO,EAAO,WAAc,SAAW,EAAO,UAAY,KACrD,EACL,OAAO,EAAO,eAAkB,UAAY,EAAO,gBAAkB,KAClE,EAAO,cACP,KACE,EACL,OAAO,EAAO,gBAAmB,SAAW,EAAO,eAAiB,KAMrE,OAJI,IAAc,MAAQ,IAAmB,KACrC,KAGD,CACN,YACA,gBACA,gBACD,CACD,MAAQ,CACP,OAAO,IACR,CACD,EAEM,EAAa,MAAO,EAAkB,IAAsB,CACjE,MAAM,EAAU,EAAU,KAAK,UAAU,EAAM,KAAM,CAAC,EAAG,OAAO,CACjE,EAKM,EAAmB,KAAO,IAAwB,CACvD,GAAI,CAKH,OAAO,MADY,MAHI,MACtB,8BAA8B,EAAY,QAC3C,EAAA,CAC4B,KAAK,EAAA,CACrB,OACb,MAAQ,CACP,OAAO,IACR,CACD,EAKM,EACL,GACI,CACJ,GAAI,CAAC,EAAgB,MAAQ,CAAC,EAAgB,UAC7C,OAGD,GAAM,CAAE,iBAAgB,iBAAkB,EAEpC,EAAe,CACpB,YAAY,EAAW,OAAO,CAAc,IAC5C,YAAY,EAAW,MAAM,GAAiB,SAAS,GACxD,EAEM,EAAgB,EAAW,KAChC,eAAeA,EAAiB,QACjC,EAgBM,EAAM,EAAM,CAbjB,2CACA,GACA,GAAG,EACH,GACA,OAAO,EAAc,YACrB,GACA,EAAW,IAAI,sBAAsB,EACpC,EAAW,KAAK,kDAAkD,EACnE,EAAW,IACV,0EACD,CAGqB,CAAC,CAAC,KAAK;CAAI,EAAG,CACnC,QAAS,EACT,OAAQ,EACR,YAAa,QACb,YAAa,SACb,MAAO,mBACP,eAAgB,MACjB,CAAC,EAED,QAAQ,IAAI,CAAG,CAChB,EAQM,EAAkB,SAA0C,CAEjE,IAAM,EAAY,EAAK,MADA,EAA2B,EACjB,uBAAqB,EAChD,EAAQ,MAAM,EAAW,CAAS,EAClC,EAAM,KAAK,IAAI,EACf,EAAiBC,EAEjB,EAAiB,IAAQ,EAAM,iBAAmB,EAClD,EAAe,EAClB,EAAM,EAAM,UAAY,OAAc,CAAC,EACvC,GAEC,EAAgB,EAAgB,GAAO,eAAiB,KAAQ,KAE/D,IACJ,EAAgB,MAAM,EAAiBD,CAAgB,EACvD,MAAM,EAAW,EAAW,CAC3B,UAAW,EACX,gBACA,gBACD,CAAC,GAGF,IAAM,EACL,GAAiB,EAAO,MAAM,CAAa,GAAK,EAAO,MAAM,CAAc,EACxE,EAAO,GAAG,EAAe,CAAc,EACvC,GAEJ,MAAO,CACN,UAAW,EACX,KAAM,CAAC,GAAgB,EACvB,gBACA,iBACA,oBACC,EAAgB,CACf,UAAW,EACX,KAAM,CAAC,GAAgB,EACvB,gBACA,gBACD,CAAC,CACH,CACD"}