1
0
Fork 0
mirror of synced 2024-05-17 02:42:53 +12:00
budibase/packages/server/src/utilities/fileSystem/clientLibrary.ts
Gerard Burns d9033b2636
Un-revert Skeleton Loader PR (#13180)
* wip

* wip

* wip

* client versions init

* wip

* wip

* wip

* wip

* wip

* linting

* remove log

* comment client version script

* lint

* skeleton loader type fix

* fix types

* lint

* fix types again

* fix manifest not being served locally

* remove preinstalled old client version

* add constant for dev client version

* linting

* Dean PR Feedback

* linting

* pr feedback

* wip

* wip

* clientVersions empty array

* delete from git

* empty array again

* fix tests

* pr feedback

---------

Co-authored-by: Andrew Kingston <andrew@kingston.dev>
2024-03-25 16:39:42 +00:00

186 lines
5.6 KiB
TypeScript

import path, { join } from "path"
import { ObjectStoreBuckets } from "../../constants"
import fs from "fs"
import { context, objectStore } from "@budibase/backend-core"
import { resolve } from "../centralPath"
import env from "../../environment"
import { TOP_LEVEL_PATH } from "./filesystem"
import { DocumentType } from "../../db/utils"
import { App } from "@budibase/types"
export function devClientLibPath() {
return require.resolve("@budibase/client")
}
/**
* Client library paths in the object store:
* Previously, the entire client library package was downloaded from NPM
* as a tarball and extracted to the object store, even though only the manifest
* was ever needed. Therefore we need to support old apps which may still have
* the manifest at this location for the first update.
*
* The new paths for the in-use version are:
* {appId}/manifest.json
* {appId}/budibase-client.js
*
* The paths for the backups are:
* {appId}/manifest.json.bak
* {appId}/budibase-client.js.bak
*
* We don't rely on NPM at all any more, as when updating to the latest version
* we pull both the manifest and client bundle from the server's dependencies
* in the local file system.
*/
/**
* Backs up the current client library version by copying both the manifest
* and client bundle to .bak extensions in the object store. Only the one
* previous version is stored as a backup, which can be reverted to.
* @param appId The app ID to backup
* @returns {Promise<void>}
*/
export async function backupClientLibrary(appId: string) {
// Copy existing manifest to tmp
let tmpManifestPath
try {
// Try to load the manifest from the new file location
tmpManifestPath = await objectStore.retrieveToTmp(
ObjectStoreBuckets.APPS,
join(appId, "manifest.json")
)
} catch (error) {
// Fallback to loading it from the old location for old apps
tmpManifestPath = await objectStore.retrieveToTmp(
ObjectStoreBuckets.APPS,
join(
appId,
"node_modules",
"budibase",
"standard-components",
"package",
"manifest.json"
)
)
}
// Copy existing client lib to tmp
const tmpClientPath = await objectStore.retrieveToTmp(
ObjectStoreBuckets.APPS,
join(appId, "budibase-client.js")
)
// Upload manifest and client library as backups
const manifestUpload = objectStore.upload({
bucket: ObjectStoreBuckets.APPS,
filename: join(appId, "manifest.json.bak"),
path: tmpManifestPath,
type: "application/json",
})
const clientUpload = objectStore.upload({
bucket: ObjectStoreBuckets.APPS,
filename: join(appId, "budibase-client.js.bak"),
path: tmpClientPath,
type: "application/javascript",
})
await Promise.all([manifestUpload, clientUpload])
}
/**
* Uploads the latest version of the component manifest and the client library
* to the object store, overwriting the existing version.
* @param appId The app ID to update
* @returns {Promise<void>}
*/
export async function updateClientLibrary(appId: string) {
let manifest, client
if (env.isDev()) {
const clientPath = devClientLibPath()
// Load the symlinked version in dev which is always the newest
manifest = join(path.dirname(path.dirname(clientPath)), "manifest.json")
client = clientPath
} else {
// Load the bundled version in prod
manifest = resolve(TOP_LEVEL_PATH, "client", "manifest.json")
client = resolve(TOP_LEVEL_PATH, "client", "budibase-client.js")
}
// Upload latest manifest and client library
const manifestUpload = objectStore.streamUpload(
ObjectStoreBuckets.APPS,
join(appId, "manifest.json"),
fs.createReadStream(manifest),
{
ContentType: "application/json",
}
)
const clientUpload = objectStore.streamUpload(
ObjectStoreBuckets.APPS,
join(appId, "budibase-client.js"),
fs.createReadStream(client),
{
ContentType: "application/javascript",
}
)
const manifestSrc = fs.promises.readFile(manifest, "utf8")
await Promise.all([manifestUpload, clientUpload, manifestSrc])
return JSON.parse(await manifestSrc)
}
/**
* Reverts the version of the client library and manifest to the previously
* used version for an app.
* @param appId The app ID to revert
* @returns {Promise<void>}
*/
export async function revertClientLibrary(appId: string) {
let manifestPath, clientPath
if (env.isDev()) {
const db = context.getAppDB()
const app = await db.get<App>(DocumentType.APP_METADATA)
clientPath = join(
__dirname,
`/oldClientVersions/${app.revertableVersion}/app.js`
)
manifestPath = join(
__dirname,
`/oldClientVersions/${app.revertableVersion}/manifest.json`
)
} else {
// Copy backups manifest to tmp directory
manifestPath = await objectStore.retrieveToTmp(
ObjectStoreBuckets.APPS,
join(appId, "manifest.json.bak")
)
// Copy backup client lib to tmp
clientPath = await objectStore.retrieveToTmp(
ObjectStoreBuckets.APPS,
join(appId, "budibase-client.js.bak")
)
}
const manifestSrc = fs.promises.readFile(manifestPath, "utf8")
// Upload backups as new versions
const manifestUpload = objectStore.upload({
bucket: ObjectStoreBuckets.APPS,
filename: join(appId, "manifest.json"),
path: manifestPath,
type: "application/json",
})
const clientUpload = objectStore.upload({
bucket: ObjectStoreBuckets.APPS,
filename: join(appId, "budibase-client.js"),
path: clientPath,
type: "application/javascript",
})
await Promise.all([manifestSrc, manifestUpload, clientUpload])
return JSON.parse(await manifestSrc)
}