@wix/cli
Version:
CLI tool for building Wix sites and applications
831 lines (814 loc) • 22.6 kB
JavaScript
import { createRequire as _createRequire } from 'node:module';
const require = _createRequire(import.meta.url);
import {
syncTypesWithAuth
} from "./chunk-UDITZ2SA.js";
import {
saveProjectModel
} from "./chunk-P7YKQHOD.js";
import {
loadProjectGridAppContent
} from "./chunk-QV3RCD44.js";
import {
createLogger
} from "./chunk-DISAL72N.js";
import {
createI18nT
} from "./chunk-HNZECZYZ.js";
import {
authenticate
} from "./chunk-U5O4HZPU.js";
import "./chunk-HEANTKSX.js";
import {
httpRequest
} from "./chunk-LU4JUEPY.js";
import "./chunk-4BLGYECY.js";
import {
createVeloCLIServer,
debounceQueue,
require_chokidar
} from "./chunk-TRRGL25Z.js";
import {
require_normalize_path
} from "./chunk-ICJSZGEK.js";
import {
getPagesFolder,
getSourceFolder,
getTypesDir
} from "./chunk-DZ3U3XXP.js";
import "./chunk-ZNLMJ43G.js";
import {
TunnelClient,
launchTunnel
} from "./chunk-MG5MUFY3.js";
import "./chunk-SR7TTQEG.js";
import {
updateFiles
} from "./chunk-DGC6KEUB.js";
import {
GridAppLayout
} from "./chunk-QRGKMYDD.js";
import {
AppType,
GridAppLayout as GridAppLayout2,
createApp,
pagesDiff
} from "./chunk-CKNI3TGO.js";
import "./chunk-3QMRQKKR.js";
import "./chunk-NMCF7XG5.js";
import "./chunk-MHV22UIU.js";
import "./chunk-K6JLY75P.js";
import "./chunk-FYLO6WOU.js";
import "./chunk-3B6VL2WO.js";
import "./chunk-7QTVQZAE.js";
import "./chunk-2KP5J2KZ.js";
import {
ErrorViewer,
createHttpClient,
isHttpError,
openBrowser,
pLimit,
writeCrashReport
} from "./chunk-CCWE4DS6.js";
import {
extractHttpError,
wixCliCliMessageDisplayed,
wixCliCodeHasBeenChanged,
wixCliFileFolderCreatedRenamedDeleted,
wixCliReadyForReloadAfterCodeChange,
wixCliUserResponseToCliMessage
} from "./chunk-U5H3SP3I.js";
import "./chunk-TIVTYCB2.js";
import "./chunk-RPTAJN5Y.js";
import {
renderSync
} from "./chunk-UC5LTXTA.js";
import "./chunk-5VIJC5EU.js";
import "./chunk-MZDJNQLB.js";
import {
require_react
} from "./chunk-QNHANFRW.js";
import "./chunk-AFPDHQYI.js";
import "./chunk-HYKBBZLS.js";
import "./chunk-C5RTKQVL.js";
import "./chunk-4EJ5VQTT.js";
import {
getDebugLogFilePath
} from "./chunk-4UTFAKA5.js";
import "./chunk-LU3R3EBR.js";
import {
getTestOverrides
} from "./chunk-XZUGLEBK.js";
import {
outputFile,
pathExists
} from "./chunk-TLLAD5LU.js";
import "./chunk-SDLCFZRL.js";
import {
CliError,
CliErrorCode
} from "./chunk-CO5A7CZG.js";
import {
__toESM,
init_esm_shims
} from "./chunk-EXLZF52D.js";
// ../cli-site-old/src/dev/index.ts
init_esm_shims();
// ../cli-site-old/src/dev/dev.ts
init_esm_shims();
// ../../node_modules/exit-hook/index.js
init_esm_shims();
import process from "node:process";
var asyncCallbacks = /* @__PURE__ */ new Set();
var callbacks = /* @__PURE__ */ new Set();
var isCalled = false;
var isRegistered = false;
async function exit(shouldManuallyExit, isSynchronous, signal) {
if (isCalled) {
return;
}
isCalled = true;
if (asyncCallbacks.size > 0 && isSynchronous) {
console.error([
"SYNCHRONOUS TERMINATION NOTICE:",
"When explicitly exiting the process via process.exit or via a parent process,",
"asynchronous tasks in your exitHooks will not run. Either remove these tasks,",
"use gracefulExit() instead of process.exit(), or ensure your parent process",
"sends a SIGINT to the process running this code."
].join(" "));
}
const exitCode = 128 + signal;
const done = (force = false) => {
if (force === true || shouldManuallyExit === true) {
process.exit(exitCode);
}
};
for (const callback of callbacks) {
callback(exitCode);
}
if (isSynchronous) {
done();
return;
}
const promises = [];
let forceAfter = 0;
for (const [callback, wait] of asyncCallbacks) {
forceAfter = Math.max(forceAfter, wait);
promises.push(Promise.resolve(callback(exitCode)));
}
const asyncTimer = setTimeout(() => {
done(true);
}, forceAfter);
await Promise.all(promises);
clearTimeout(asyncTimer);
done();
}
function addHook(options) {
const { onExit, wait, isSynchronous } = options;
const asyncCallbackConfig = [onExit, wait];
if (isSynchronous) {
callbacks.add(onExit);
} else {
asyncCallbacks.add(asyncCallbackConfig);
}
if (!isRegistered) {
isRegistered = true;
process.once("beforeExit", exit.bind(void 0, true, false, -128));
process.once("SIGINT", exit.bind(void 0, true, false, 2));
process.once("SIGTERM", exit.bind(void 0, true, false, 15));
process.once("exit", exit.bind(void 0, false, true, 0));
process.on("message", (message) => {
if (message === "shutdown") {
exit(true, true, -128);
}
});
}
return () => {
if (isSynchronous) {
callbacks.delete(onExit);
} else {
asyncCallbacks.delete(asyncCallbackConfig);
}
};
}
function asyncExitHook(onExit, options = {}) {
if (typeof onExit !== "function") {
throw new TypeError("onExit must be a function");
}
if (!(typeof options.wait === "number" && options.wait > 0)) {
throw new TypeError("wait must be set to a positive numeric value");
}
return addHook({
onExit,
wait: options.wait,
isSynchronous: false
});
}
// ../cli-site-old/src/dev/dev.ts
var import_react = __toESM(require_react(), 1);
// ../cli-site-old/src/environment.ts
init_esm_shims();
var DEV_EDITOR_BASE_URL = "https://wix.com/editor/";
function getDevEditorBaseUrl() {
return getTestOverrides().devEditorBaseUrl ?? DEV_EDITOR_BASE_URL;
}
// ../cli-site-old/src/gridapp/createGridApp.ts
init_esm_shims();
// ../cli-site-old/src/gridapp/error-handlers/maxFileSizeErrorHandler.ts
init_esm_shims();
function catchFilesMaxSizeError(err, files = []) {
if (!files.length) {
return;
}
const httpError = extractHttpError(err);
if (!httpError) {
return;
}
const filesMaxSizeRawViolations = httpError.response?.data?.details?.validationError?.fieldViolations?.filter(
(v) => v.violatedRule === "MAX_LENGTH"
);
if (!filesMaxSizeRawViolations?.length) {
return;
}
const maxSizeViolationsData = tryExtractMaxSizeViolationMetadata(
filesMaxSizeRawViolations
);
throw new CliError({
code: CliErrorCode.GridAppFilesMaxLengthExceeded({
maxSizeViolationsData,
filePaths: files.map((f) => f.path ?? "[unknown file path]")
}),
cause: httpError
});
}
function tryExtractMaxSizeViolationMetadata(filesMaxSizeViolations) {
const fileIndexRegex = /\[(?<fileIndex>\d+)\].content/;
const expectedAndReceivedSizeRegex = /has size (?<receivedSize>\d+), expected (?<expectedSize>\d+) or less/;
const violationsData = {
expectedSize: void 0,
files: []
};
for (const filesMaxSizeViolation of filesMaxSizeViolations) {
const fileIndexMatchResult = fileIndexRegex.exec(
filesMaxSizeViolation.field
);
const expectedAndReceivedSizeMatchResult = expectedAndReceivedSizeRegex.exec(filesMaxSizeViolation.description);
if (!(fileIndexMatchResult?.groups?.fileIndex && expectedAndReceivedSizeMatchResult?.groups?.receivedSize && expectedAndReceivedSizeMatchResult.groups.expectedSize)) {
return null;
}
violationsData.expectedSize ??= Math.trunc(
parseInt(expectedAndReceivedSizeMatchResult.groups.expectedSize, 10) / 1e3
);
violationsData.files.push({
receivedSize: Math.trunc(
parseInt(expectedAndReceivedSizeMatchResult.groups.receivedSize, 10) / 1e3
),
fileIndex: parseInt(fileIndexMatchResult.groups.fileIndex, 10)
});
}
return violationsData;
}
// ../cli-site-old/src/gridapp/createGridApp.ts
async function createAppWithParams(params, opts) {
let app;
try {
const response = await httpRequest(
{ type: "code", authState: opts.authState },
createApp(params)
);
app = response.data.app;
} catch (err) {
catchFilesMaxSizeError(err, params.content?.files);
throw err;
}
if (!app?.id) {
throw new CliError({
code: CliErrorCode.InvalidCreateAppResponse(),
info: { app },
cause: null
});
}
return app.id;
}
async function createMutableGridApp(projectFolder, opts) {
const content = await loadProjectGridAppContent(projectFolder);
return createAppWithParams(
{
app: {
mutable: true,
appType: AppType.VELO_ISOLATED
},
content
},
opts
);
}
// ../cli-site-old/src/gridapp/startGridAppUpdater.ts
init_esm_shims();
import { readFile } from "node:fs/promises";
import { join } from "node:path";
var import_chokidar = __toESM(require_chokidar(), 1);
var import_normalize_path = __toESM(require_normalize_path(), 1);
var WATCH_FS_EVENTS_DEBOUNCE_TIME = 1e3;
var getSectionName = (path) => {
if (path.startsWith("src/pages")) {
return "public";
}
if (path.startsWith("src/backend")) {
return "backend";
}
return "other";
};
function startGridAppUpdater(model, gridAppId, opts, logger, biEvents) {
const { projectFolder } = model;
const limit = pLimit(1);
const watcher = (0, import_chokidar.watch)(getSourceFolder(projectFolder), {
disableGlobbing: true,
cwd: projectFolder,
ignoreInitial: true
}).on(
"all",
debounceQueue(async (events) => {
await limit(async () => {
const logSynced = logger.logSyncingLocalCode();
const { added, changed, removed } = normalizeChokidarBatchedEvents(events);
const addedArray = Array.from(added.values()).map((path) => ({
path,
type: "create"
}));
const changedArray = Array.from(changed.values()).map((path) => ({
path,
type: "update"
}));
const removedArray = Array.from(removed.values()).map((path) => ({
path,
type: "delete"
}));
for (const val of [...addedArray, ...changedArray, ...removedArray]) {
biEvents.file({
model,
action: val.type,
path: val.path,
oldPath: "",
sectionName: getSectionName(val.path)
});
if (val.type === "update") {
biEvents.codeChanged(model, val.path);
}
}
try {
await writeFiles({
filesToUpdate: await Promise.all(
addedArray.concat(changedArray).map(async (val) => ({
path: (0, import_normalize_path.default)(val.path),
content: await readFile(
join(projectFolder, val.path),
"utf8"
)
}))
),
removedArray,
gridAppId,
authState: opts.authState
});
const message = logSynced.success();
biEvents.messageDisplayed({ message, model });
biEvents.readyForReloadAfterCodeChanged(model);
} catch (e) {
logSynced.fail();
const error = new CliError({
code: CliErrorCode.GridAppFailedToUpdateFiles(),
cause: e,
info: {
added,
changed,
removed
}
});
opts.onError(error);
}
});
}, WATCH_FS_EVENTS_DEBOUNCE_TIME)
).on("error", (e) => {
const error = new CliError({
code: CliErrorCode.FailedToWatchFiles(),
cause: e
});
opts.onError(error);
});
return { close: () => watcher.close() };
}
function normalizeChokidarBatchedEvents(events) {
return events.reduce(
(result, [eventType, filePath]) => {
switch (eventType) {
case "add": {
result.added.add(filePath);
break;
}
case "change": {
result.changed.add(filePath);
break;
}
case "unlink": {
result.added.delete(filePath);
result.changed.delete(filePath);
result.removed.add(filePath);
break;
}
case "unlinkDir": {
const filePathAsDir = filePath.endsWith("/") ? filePath : `${filePath}/`;
for (const filePath2 of result.added) {
if (filePath2.startsWith(filePathAsDir)) {
result.added.delete(filePath2);
}
}
for (const filePath2 of result.changed) {
if (filePath2.startsWith(filePathAsDir)) {
result.changed.delete(filePath2);
}
}
result.removed.add(filePath);
break;
}
case "addDir": {
break;
}
}
return result;
},
{
added: /* @__PURE__ */ new Set(),
changed: /* @__PURE__ */ new Set(),
removed: /* @__PURE__ */ new Set()
}
);
}
async function writeFiles({
filesToUpdate,
removedArray,
gridAppId,
authState
}) {
try {
await httpRequest(
{
type: "code",
authState
},
updateFiles({
gridAppId,
layout: GridAppLayout.GITHUB,
filesToUpdate,
ignoreForbiddenPaths: true,
pathsToDelete: removedArray.map((val) => val.path)
})
);
} catch (err) {
catchFilesMaxSizeError(err, filesToUpdate);
throw err;
}
}
// ../cli-site-old/src/key-watcher.ts
init_esm_shims();
import readline from "node:readline";
import { stdin } from "node:process";
var KeyWatcher = class {
actions = /* @__PURE__ */ new Map();
watchExitProcess() {
return new Promise((resolve) => {
this.on("c", (key) => {
if (key.ctrl) {
resolve();
}
});
});
}
on(key, callback) {
this.actions.set(key, callback);
}
watch() {
const rl = readline.createInterface(stdin);
readline.emitKeypressEvents(stdin, rl);
if (stdin.isTTY) {
stdin.setRawMode(true);
stdin.setEncoding("utf8");
}
stdin.on("keypress", this.handleKeyPress);
return {
ctrlCPromise: this.watchExitProcess()
};
}
unwatch() {
if (stdin.isTTY) {
stdin.setRawMode(false);
}
stdin.off("keypress", this.handleKeyPress);
stdin.pause();
this.actions.clear();
}
handleKeyPress = (_, key) => {
this.actions.get(key.name)?.(key);
};
};
// ../cli-site-old/src/bi.ts
init_esm_shims();
import { randomUUID } from "node:crypto";
var sitesBiEvents = (biLogger) => ({
file: ({
model,
action,
path,
sectionName,
oldPath
}) => {
void biLogger.report(
wixCliFileFolderCreatedRenamedDeleted({
action,
path,
sectionName,
oldPath,
siteRevision: Number(model.revision)
})
);
},
codeChanged: (model, fileName) => {
void biLogger.report(
wixCliCodeHasBeenChanged({
fileName,
siteRevision: Number(model.revision)
})
);
},
readyForReloadAfterCodeChanged: (model) => {
void biLogger.report(
wixCliReadyForReloadAfterCodeChange({
siteRevision: Number(model.revision)
})
);
},
messageDisplayed: ({
message,
model
}) => {
void biLogger.report(
wixCliCliMessageDisplayed({
message,
messageId: randomUUID(),
siteRevision: Number(model.revision)
})
);
},
userResponse: ({
model,
action,
message
}) => {
void biLogger.report(
wixCliUserResponseToCliMessage({
action,
message,
messageId: randomUUID(),
siteRevision: Number(model.revision)
})
);
}
});
// ../cli-site-old/src/dev/sync-all-to-revision.ts
init_esm_shims();
import { rm as rm2 } from "node:fs/promises";
// ../cli-site-old/src/sources/index.ts
init_esm_shims();
import { readdir } from "node:fs/promises";
// ../cli-site-old/src/sources/pages-diff.ts
init_esm_shims();
import { join as join2 } from "node:path";
import { rm, rename } from "node:fs/promises";
async function createPages(projectFolder, pages) {
await Promise.all(
pages.map((page) => {
if (!page.pageId?.path || !page.content) {
return Promise.resolve();
}
return outputFile(join2(projectFolder, page.pageId.path), page.content);
})
);
}
async function renamePages(projectFolder, pages) {
await Promise.all(
pages.map(async (page) => {
if (!page.sourcePath?.path || !page.targetPath?.path) {
return;
}
const sourcePath = join2(projectFolder, page.sourcePath.path);
const targetPath = join2(projectFolder, page.targetPath.path);
if (await pathExists(targetPath)) {
return rm(sourcePath, { force: true });
}
return rename(sourcePath, targetPath);
})
);
}
async function deletePages(projectFolder, pages) {
await Promise.all(
pages.map((page) => {
if (!page.path) {
return Promise.resolve();
}
return rm(join2(projectFolder, page.path), { force: true });
})
);
}
// ../cli-site-old/src/sources/index.ts
async function syncPages(model, opts) {
const pagesFolder = getPagesFolder(model.projectFolder);
if (!await pathExists(pagesFolder)) {
throw new CliError({
code: CliErrorCode.NoPagesDirectoryFound({
srcDir: getSourceFolder(model.projectFolder)
}),
cause: null
});
}
const params = {
layout: GridAppLayout2.GITHUB,
sourcePagesPaths: await readdir(pagesFolder),
targetRevision: model.revision
};
const { data } = await httpRequest(
{
authState: opts.authState,
type: "code"
},
pagesDiff(params)
).catch((e) => {
throw new CliError({
code: CliErrorCode.FailedToGetPagesDiff(),
cause: e,
info: { ...params }
});
});
await Promise.all([
createPages(model.projectFolder, data.pagesDiff?.created ?? []),
renamePages(model.projectFolder, data.pagesDiff?.renamed ?? []),
deletePages(model.projectFolder, data.pagesDiff?.deleted ?? [])
]);
}
// ../cli-site-old/src/dev/sync-all-to-revision.ts
async function syncAllToRevision(model, opts, logger) {
const logTypesSynced = logger.logSyncingTypesToRevision(model.revision);
try {
await syncTypesWithAuth(model, { authState: opts.authState });
logTypesSynced.success();
} catch (error) {
writeCrashReport(
getDebugLogFilePath(model.projectFolder),
error,
/* @__PURE__ */ new Date()
);
logTypesSynced.fail();
await rm2(getTypesDir(model.projectFolder), {
recursive: true,
force: true
}).catch((e) => {
writeCrashReport(getDebugLogFilePath(model.projectFolder), e, /* @__PURE__ */ new Date());
logger.logRecoverableFailureToRemoveTypesDir(e);
});
}
const logPagesSynced = logger.logSyncingPagesToRevision(model.revision);
try {
await syncPages(model, { authState: opts.authState });
logPagesSynced.success();
} catch (error) {
logPagesSynced.fail();
throw error;
}
}
// ../cli-site-old/src/dev/dev.ts
async function dev(initialModel, { biLogger, errorReporter, loginMode }, {
https = false,
tunnel: useTunnel = false
}) {
let model = initialModel;
const authState = await authenticate({
metaSiteId: model.metaSiteId,
biLogger,
errorReporter,
loginMode
});
const t = createI18nT();
const logger = createLogger({ t });
const biEvents = sitesBiEvents(biLogger);
const server = createVeloCLIServer({ https });
let gridAppId;
try {
gridAppId = await createMutableGridApp(model.projectFolder, {
authState
});
} catch (error) {
const message = isHttpError(error) ? error.response?.data?.message : void 0;
throw new CliError({
code: CliErrorCode.FailedToCreateGridApp({
error: message
}),
cause: error
});
}
await syncAllToRevision(model, { authState }, logger);
const { close } = startGridAppUpdater(
model,
gridAppId,
{
authState,
onError(error) {
logger.logNewLine();
errorReporter.reportError(error);
writeCrashReport(
getDebugLogFilePath(model.projectFolder),
error,
/* @__PURE__ */ new Date()
);
renderSync((0, import_react.createElement)(ErrorViewer, { error }));
}
},
logger,
biEvents
);
const onServerDisconnected = (devEditorUrl) => {
const message = logger.logNoOpenedTab(devEditorUrl);
biEvents.messageDisplayed({ model, message });
};
const onSyncDevEditorChanges = async (revision) => {
if (revision !== model.revision) {
const newModel = { ...model, revision };
await saveProjectModel(newModel);
const message = logger.logUpdatedLocalCodeToRevision({
revision: newModel.revision
});
biEvents.messageDisplayed({ message, model });
await syncAllToRevision(newModel, { authState }, logger);
model = newModel;
}
};
const openLocalEditor = async (serverPort) => {
biEvents.userResponse({
action: "Browser opened",
message: "Opening the Local Editor",
model
});
const devEditorUrl = getDevEditorUrl(serverPort);
if (https) {
await openBrowser(new URL(`https://localhost:${serverPort}`).href);
} else {
await openBrowser(devEditorUrl);
}
};
let keyWatcher;
let tunnel;
const getDevEditorUrl = (serverPort) => {
const url = new URL(model.metaSiteId, getDevEditorBaseUrl());
if (tunnel) {
url.searchParams.append("localEditorDestination", tunnel.domain);
} else {
url.searchParams.append("localPort", serverPort.toString());
}
url.searchParams.append("secureSocket", https.toString());
return url.toString();
};
try {
const { port: serverPort } = await server.serve(gridAppId, {
getDevEditorUrl
});
if (useTunnel) {
const httpClient = createHttpClient({
type: "backoffice",
getAppToken: authState.getAccessToken
});
const tunnelClient = new TunnelClient(httpClient);
tunnel = await launchTunnel(serverPort, tunnelClient);
}
const devEditorUrl = getDevEditorUrl(serverPort);
server.on("disconnected", () => onServerDisconnected(devEditorUrl));
server.on("syncDevEditorChanges", onSyncDevEditorChanges);
keyWatcher = new KeyWatcher();
logger.logOpeningBrowser(https);
await openLocalEditor(serverPort);
const { ctrlCPromise } = keyWatcher.watch();
keyWatcher.on("e", () => openLocalEditor(serverPort));
asyncExitHook(
async () => {
await server.close();
tunnel?.close();
},
{ wait: 500 }
);
await ctrlCPromise;
} finally {
keyWatcher?.unwatch();
await Promise.all([server.close(), close(), tunnel?.close()]);
}
}
export {
dev
};
//# sourceMappingURL=dev-H62QAPM2.js.map