UNPKG

sanity

Version:

Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches

346 lines (345 loc) • 10.5 kB
"use strict"; var fs = require("node:fs/promises"), path = require("node:path"), node_stream = require("node:stream"), FormData = require("form-data"), nanoid = require("nanoid"), readPkgUp = require("read-pkg-up"), _internal = require("./_internal.js"); function _interopDefaultCompat(e) { return e && typeof e == "object" && "default" in e ? e : { default: e }; } var fs__default = /* @__PURE__ */ _interopDefaultCompat(fs), path__default = /* @__PURE__ */ _interopDefaultCompat(path), FormData__default = /* @__PURE__ */ _interopDefaultCompat(FormData), readPkgUp__default = /* @__PURE__ */ _interopDefaultCompat(readPkgUp); const debug = _internal.debug.extend("deploy"); function promiseWithResolvers() { let resolve, reject; return { promise: new Promise((res, rej) => { resolve = res, reject = rej; }), resolve, reject }; } async function getUserApplication({ client, appHost, appId }) { let query, uri = "/user-applications"; appId ? (uri = `/user-applications/${appId}`, query = { appType: "coreApp" }) : appHost ? query = { appHost } : query = { default: "true" }; try { return await client.request({ uri, query }); } catch (e) { if (e?.statusCode === 404) return null; throw debug("Error getting user application", e), e; } } async function getUserApplications({ client, organizationId }) { const query = organizationId ? { organizationId, appType: "coreApp" } : { appType: "studio" }; try { return await client.request({ uri: "/user-applications", query }); } catch (e) { if (e?.statusCode === 404) return null; throw debug("Error getting user applications", e), e; } } function createUserApplication(client, body, organizationId) { const query = organizationId ? { organizationId, appType: "coreApp" } : { appType: "studio" }; return client.request({ uri: "/user-applications", method: "POST", body, query }); } async function selectExistingApplication({ client, prompt, message, createNewLabel, organizationId }) { const userApplications = await getUserApplications({ client, organizationId }); if (!userApplications?.length) return null; const choices = userApplications.map((app) => ({ value: app.appHost, name: app.title ?? app.appHost })), selected = await prompt.single({ message, type: "list", choices: [{ value: "new", name: createNewLabel }, new prompt.Separator(), ...choices] }); return selected === "new" ? null : userApplications.find((app) => app.appHost === selected); } async function getOrCreateStudio({ client, spinner, context }) { const { output, prompt } = context, existingUserApplication = await getUserApplication({ client }); if (spinner.succeed(), existingUserApplication) return existingUserApplication; const selectedApp = await selectExistingApplication({ client, prompt, message: "Select existing studio hostname", createNewLabel: "Create new studio hostname" }); if (selectedApp) return selectedApp; output.print("Your project has not been assigned a studio hostname."), output.print("To deploy your Sanity Studio to our hosted sanity.studio service,"), output.print("you will need one. Please enter the part you want to use."); const { promise, resolve } = promiseWithResolvers(); return await prompt.single({ type: "input", filter: (inp) => inp.replace(/\.sanity\.studio$/i, ""), message: "Studio hostname (<value>.sanity.studio):", // if a string is returned here, it is relayed to the user and prompt allows // the user to try again until this function returns true validate: async (appHost) => { try { const response = await createUserApplication(client, { appHost, urlType: "internal", type: "studio" }); return resolve(response), !0; } catch (e) { if ([402, 409].includes(e?.statusCode)) return e?.response?.body?.message || "Bad request"; throw debug("Error creating user application", e), e; } } }), await promise; } async function getOrCreateApplication({ client, context, spinner }) { const { prompt, cliConfig } = context, organizationId = cliConfig && "app" in cliConfig && cliConfig.app?.organizationId; spinner.succeed(); const selectedApp = await selectExistingApplication({ client, prompt, message: "Select an existing deployed application", createNewLabel: "Create new deployed application", organizationId: organizationId || void 0 }); if (selectedApp) return selectedApp; const title = await prompt.single({ type: "input", message: "Enter a title for your application:", validate: (input) => input.length > 0 || "Title is required" }), { promise, resolve, reject } = promiseWithResolvers(), tryCreateApp = async () => { const appHost = (() => { const firstChar = nanoid.customAlphabet("abcdefghijklmnopqrstuvwxyz", 1)(), rest = nanoid.customAlphabet("abcdefghijklmnopqrstuvwxyz0123456789", 11)(); return `${firstChar}${rest}`; })(); try { const response2 = await createUserApplication(client, { appHost, urlType: "internal", title, type: "coreApp" }, organizationId || void 0); return resolve(response2), !0; } catch (e) { if ([402, 409].includes(e?.statusCode)) return debug("App host taken, retrying with new host"), tryCreateApp(); throw debug("Error creating core application", e), reject(e), e; } }; spinner.start("Creating application"), await tryCreateApp(); const response = await promise; return spinner.succeed(), response; } async function getOrCreateStudioFromConfig({ client, context, spinner, appHost }) { const { output } = context, existingUserApplication = await getUserApplication({ client, appHost }); if (spinner.succeed(), existingUserApplication) return existingUserApplication; output.print("Your project has not been assigned a studio hostname."), output.print(`Creating https://${appHost}.sanity.studio`), output.print(""), spinner.start("Creating studio hostname"); try { const response = await createUserApplication(client, { appHost, urlType: "internal", type: "studio" }); return spinner.succeed(), response; } catch (e) { throw spinner.fail(), [402, 409].includes(e?.statusCode) ? new Error(e?.response?.body?.message || "Bad request") : (debug("Error creating user application from config", e), e); } } async function getOrCreateAppFromConfig({ client, context, spinner, appId }) { const { output } = context; if (appId) { const existingUserApplication = await getUserApplication({ client, appId }); if (spinner.succeed(), existingUserApplication) return existingUserApplication; } return output.print("The id provided in your configuration is not recognized."), output.print("Checking existing applications..."), getOrCreateApplication({ client, context, spinner }); } async function getOrCreateUserApplicationFromConfig(options) { const { context } = options; if (_internal.determineIsApp(context.cliConfig)) return getOrCreateAppFromConfig(options); if (!options.appHost) throw new Error("Studio host was detected, but is invalid"); return getOrCreateStudioFromConfig({ ...options, appHost: options.appHost }); } async function createDeployment({ client, tarball, applicationId, isAutoUpdating, version, isApp }) { const formData = new FormData__default.default(); return formData.append("isAutoUpdating", isAutoUpdating.toString()), formData.append("version", version), formData.append("tarball", tarball, { contentType: "application/gzip", filename: "app.tar.gz" }), client.request({ uri: `/user-applications/${applicationId}/deployments`, method: "POST", headers: formData.getHeaders(), body: formData.pipe(new node_stream.PassThrough()), query: isApp ? { appType: "coreApp" } : { appType: "studio" } }); } async function deleteUserApplication({ applicationId, client, appType }) { await client.request({ uri: `/user-applications/${applicationId}`, query: { appType }, method: "DELETE" }); } async function getInstalledSanityVersion() { const sanityPkgPath = (await readPkgUp__default.default({ cwd: __dirname }))?.path; if (!sanityPkgPath) throw new Error("Unable to resolve `sanity` module root"); const pkg = JSON.parse(await fs__default.default.readFile(sanityPkgPath, "utf-8")); if (typeof pkg?.version != "string") throw new Error("Unable to find version of `sanity` module"); return pkg.version; } async function dirIsEmptyOrNonExistent(sourceDir) { try { if (!(await fs__default.default.stat(sourceDir)).isDirectory()) throw new Error(`Directory ${sourceDir} is not a directory`); } catch (err) { if (err.code === "ENOENT") return !0; throw err; } return (await fs__default.default.readdir(sourceDir)).length === 0; } async function checkDir(sourceDir) { try { if (!(await fs__default.default.stat(sourceDir)).isDirectory()) throw new Error(`Directory ${sourceDir} is not a directory`); } catch (err) { throw err.code === "ENOENT" ? new Error(`Directory "${sourceDir}" does not exist`) : err; } try { await fs__default.default.stat(path__default.default.join(sourceDir, "index.html")); } catch (err) { throw err.code === "ENOENT" ? new Error([`"${sourceDir}/index.html" does not exist -`, "[SOURCE_DIR] must be a directory containing", 'a Sanity studio built using "sanity build"'].join(" ")) : err; } } exports.checkDir = checkDir; exports.createDeployment = createDeployment; exports.debug = debug; exports.deleteUserApplication = deleteUserApplication; exports.dirIsEmptyOrNonExistent = dirIsEmptyOrNonExistent; exports.getInstalledSanityVersion = getInstalledSanityVersion; exports.getOrCreateApplication = getOrCreateApplication; exports.getOrCreateStudio = getOrCreateStudio; exports.getOrCreateUserApplicationFromConfig = getOrCreateUserApplicationFromConfig; exports.getUserApplication = getUserApplication; //# sourceMappingURL=helpers.js.map