@anvil-works/anvil-cli 0.5.6 → 0.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +140 -45
- package/dist/index.js +75 -8
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -33132,6 +33132,16 @@ function __webpack_require__(moduleId) {
|
|
|
33132
33132
|
(()=>{
|
|
33133
33133
|
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
33134
33134
|
})();
|
|
33135
|
+
(()=>{
|
|
33136
|
+
__webpack_require__.r = (exports1)=>{
|
|
33137
|
+
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
33138
|
+
value: 'Module'
|
|
33139
|
+
});
|
|
33140
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
33141
|
+
value: true
|
|
33142
|
+
});
|
|
33143
|
+
};
|
|
33144
|
+
})();
|
|
33135
33145
|
(()=>{
|
|
33136
33146
|
__webpack_require__.nmd = (module)=>{
|
|
33137
33147
|
module.paths = [];
|
|
@@ -33142,6 +33152,10 @@ function __webpack_require__(moduleId) {
|
|
|
33142
33152
|
var __webpack_exports__ = {};
|
|
33143
33153
|
(()=>{
|
|
33144
33154
|
"use strict";
|
|
33155
|
+
__webpack_require__.r(__webpack_exports__);
|
|
33156
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
33157
|
+
buildProgram: ()=>buildProgram
|
|
33158
|
+
});
|
|
33145
33159
|
const ANSI_BACKGROUND_OFFSET = 10;
|
|
33146
33160
|
const wrapAnsi16 = (offset = 0)=>(code)=>`\u001B[${code + offset}m`;
|
|
33147
33161
|
const wrapAnsi256 = (offset = 0)=>(code)=>`\u001B[${38 + offset};5;${code}m`;
|
|
@@ -47629,12 +47643,14 @@ var __webpack_exports__ = {};
|
|
|
47629
47643
|
editSession;
|
|
47630
47644
|
username;
|
|
47631
47645
|
reconnectAttempts = 0;
|
|
47646
|
+
connectAttempts = 0;
|
|
47632
47647
|
reconnectTimer = null;
|
|
47633
47648
|
heartbeatTimer = null;
|
|
47634
47649
|
pongTimeoutTimer = null;
|
|
47635
47650
|
reconnectDelayMs;
|
|
47636
47651
|
isClosing = false;
|
|
47637
47652
|
sessionId;
|
|
47653
|
+
lastDisconnectSummary = null;
|
|
47638
47654
|
RECONNECT_DELAY_BASE_MS = 5000;
|
|
47639
47655
|
RECONNECT_DELAY_MAX_MS = 60000;
|
|
47640
47656
|
HEARTBEAT_INTERVAL_MS = 30000;
|
|
@@ -47652,6 +47668,7 @@ var __webpack_exports__ = {};
|
|
|
47652
47668
|
}
|
|
47653
47669
|
async connect() {
|
|
47654
47670
|
this.isClosing = false;
|
|
47671
|
+
this.connectAttempts++;
|
|
47655
47672
|
if (this.ws?.readyState === ws_wrapper.OPEN) return void logger_logger.debug(`[WebSocket ${this.sessionId}]`, "WebSocket already open, skipping connection");
|
|
47656
47673
|
if (this.ws) {
|
|
47657
47674
|
logger_logger.debug(`[WebSocket ${this.sessionId}]`, "Closing existing WebSocket before reconnecting");
|
|
@@ -47660,6 +47677,7 @@ var __webpack_exports__ = {};
|
|
|
47660
47677
|
this.authToken = await auth_getValidAuthToken(this.anvilUrl, this.username);
|
|
47661
47678
|
const wsUrl = getWebSocketUrl(this.appId, this.authToken, this.anvilUrl);
|
|
47662
47679
|
logger_logger.debug(`[WebSocket ${this.sessionId}]`, `Connecting to: ${wsUrl.replace(this.authToken, "[TOKEN]")}`);
|
|
47680
|
+
logger_logger.verbose(chalk_source.gray(`WebSocket connecting to ${this.getConnectionTarget(wsUrl)} (app ${this.appId}, branch ${this.currentBranch}, session ${this.sessionId}, connect attempt ${this.connectAttempts})`));
|
|
47663
47681
|
this.ws = new ws_wrapper(wsUrl);
|
|
47664
47682
|
this.ws.on("open", ()=>{
|
|
47665
47683
|
logger_logger.verbose(chalk_source.green("🔌 Connected to Anvil WebSocket"));
|
|
@@ -47676,6 +47694,21 @@ var __webpack_exports__ = {};
|
|
|
47676
47694
|
this.ws?.send(JSON.stringify(subscribeMsg));
|
|
47677
47695
|
this.emit("connected", void 0);
|
|
47678
47696
|
});
|
|
47697
|
+
this.ws.on("unexpected-response", (request, response)=>{
|
|
47698
|
+
const summary = this.summarizeUnexpectedResponse(response, wsUrl);
|
|
47699
|
+
this.lastDisconnectSummary = summary;
|
|
47700
|
+
logger_logger.error(chalk_source.red(summary));
|
|
47701
|
+
response.resume();
|
|
47702
|
+
request.destroy();
|
|
47703
|
+
if (this.isClosing) return;
|
|
47704
|
+
this.stopHeartbeat();
|
|
47705
|
+
this.ws = null;
|
|
47706
|
+
this.emit("disconnected", {
|
|
47707
|
+
code: 1006,
|
|
47708
|
+
reason: summary
|
|
47709
|
+
});
|
|
47710
|
+
this.scheduleReconnect();
|
|
47711
|
+
});
|
|
47679
47712
|
this.ws.on("message", (data)=>{
|
|
47680
47713
|
this.markSocketResponsive();
|
|
47681
47714
|
try {
|
|
@@ -47700,6 +47733,7 @@ var __webpack_exports__ = {};
|
|
|
47700
47733
|
return;
|
|
47701
47734
|
}
|
|
47702
47735
|
if (this.isClosing) return;
|
|
47736
|
+
this.lastDisconnectSummary = this.lastDisconnectSummary ?? this.formatCloseSummary(code, reason.toString());
|
|
47703
47737
|
this.emit("disconnected", {
|
|
47704
47738
|
code,
|
|
47705
47739
|
reason: reason.toString()
|
|
@@ -47709,8 +47743,13 @@ var __webpack_exports__ = {};
|
|
|
47709
47743
|
this.ws.on("error", (error)=>{
|
|
47710
47744
|
logger_logger.debug(`[WebSocket ${this.sessionId}]`, `Error: ${error.message}`);
|
|
47711
47745
|
if (this.isClosing) return;
|
|
47712
|
-
if (error.message.includes("
|
|
47713
|
-
|
|
47746
|
+
if (error.message.includes("Unexpected server response")) return;
|
|
47747
|
+
if (error.message.includes("502")) logger_logger.error(chalk_source.red(`WebSocket connection failed (502 Bad Gateway) - the server could not open the live update connection (${this.getConnectionContext()})`));
|
|
47748
|
+
else {
|
|
47749
|
+
const details = this.getConnectionContext();
|
|
47750
|
+
logger_logger.error(chalk_source.red(`WebSocket error: ${error.message} (${details})`));
|
|
47751
|
+
}
|
|
47752
|
+
this.lastDisconnectSummary = `WebSocket error: ${error.message}`;
|
|
47714
47753
|
this.emit("error", {
|
|
47715
47754
|
error
|
|
47716
47755
|
});
|
|
@@ -47765,7 +47804,7 @@ var __webpack_exports__ = {};
|
|
|
47765
47804
|
if (this.reconnectTimer || this.isClosing) return;
|
|
47766
47805
|
this.reconnectAttempts++;
|
|
47767
47806
|
const delayMs = this.reconnectDelayMs;
|
|
47768
|
-
logger_logger.verbose(chalk_source.gray(`WebSocket disconnected, reconnecting in ${Math.round(delayMs / 1000)}s (attempt ${this.
|
|
47807
|
+
logger_logger.verbose(chalk_source.gray(`WebSocket disconnected (${this.lastDisconnectSummary ?? "unknown cause"}), reconnecting in ${Math.round(delayMs / 1000)}s (${this.getConnectionContext()}, next connect attempt ${this.connectAttempts + 1})...`));
|
|
47769
47808
|
this.reconnectTimer = setTimeout(()=>{
|
|
47770
47809
|
this.reconnectTimer = null;
|
|
47771
47810
|
this.connect().catch((error)=>{
|
|
@@ -47774,8 +47813,47 @@ var __webpack_exports__ = {};
|
|
|
47774
47813
|
});
|
|
47775
47814
|
});
|
|
47776
47815
|
}, delayMs);
|
|
47816
|
+
this.lastDisconnectSummary = null;
|
|
47777
47817
|
this.reconnectDelayMs = Math.min(Math.round(1.5 * this.reconnectDelayMs), this.RECONNECT_DELAY_MAX_MS);
|
|
47778
47818
|
}
|
|
47819
|
+
getConnectionContext() {
|
|
47820
|
+
return `app ${this.appId}, branch ${this.currentBranch}, session ${this.sessionId}`;
|
|
47821
|
+
}
|
|
47822
|
+
getConnectionTarget(wsUrl) {
|
|
47823
|
+
const url = new URL(wsUrl);
|
|
47824
|
+
return `${url.origin}${url.pathname}`;
|
|
47825
|
+
}
|
|
47826
|
+
formatCloseSummary(code, reason) {
|
|
47827
|
+
const suffix = reason ? `, reason=${reason}` : "";
|
|
47828
|
+
return `close code=${code}${suffix}`;
|
|
47829
|
+
}
|
|
47830
|
+
summarizeUnexpectedResponse(response, wsUrl) {
|
|
47831
|
+
const statusCode = response.statusCode ?? "unknown";
|
|
47832
|
+
const statusMessage = response.statusMessage ?? "Unknown";
|
|
47833
|
+
const details = [
|
|
47834
|
+
`target ${this.getConnectionTarget(wsUrl)}`,
|
|
47835
|
+
this.getConnectionContext(),
|
|
47836
|
+
this.getHandshakeMetadata(response)
|
|
47837
|
+
].filter(Boolean).join(", ");
|
|
47838
|
+
return `WebSocket handshake failed (${statusCode} ${statusMessage}; ${details})`;
|
|
47839
|
+
}
|
|
47840
|
+
getHandshakeMetadata(response) {
|
|
47841
|
+
const headers = response.headers;
|
|
47842
|
+
const detailParts = [];
|
|
47843
|
+
const requestId = this.getHeaderValue(headers["x-request-id"]) || this.getHeaderValue(headers["x-amzn-requestid"]) || this.getHeaderValue(headers["cf-ray"]);
|
|
47844
|
+
const retryAfter = this.getHeaderValue(headers["retry-after"]);
|
|
47845
|
+
const server = this.getHeaderValue(headers["server"]);
|
|
47846
|
+
const via = this.getHeaderValue(headers["via"]);
|
|
47847
|
+
if (requestId) detailParts.push(`request-id ${requestId}`);
|
|
47848
|
+
if (retryAfter) detailParts.push(`retry-after ${retryAfter}`);
|
|
47849
|
+
if (server) detailParts.push(`server ${server}`);
|
|
47850
|
+
if (via) detailParts.push(`via ${via}`);
|
|
47851
|
+
return detailParts.join(", ");
|
|
47852
|
+
}
|
|
47853
|
+
getHeaderValue(header) {
|
|
47854
|
+
if (Array.isArray(header)) return header[0] ?? null;
|
|
47855
|
+
return header ?? null;
|
|
47856
|
+
}
|
|
47779
47857
|
startHeartbeat() {
|
|
47780
47858
|
this.stopHeartbeat();
|
|
47781
47859
|
this.heartbeatTimer = setInterval(()=>{
|
|
@@ -47917,9 +47995,9 @@ var __webpack_exports__ = {};
|
|
|
47917
47995
|
result.localOnlyChanges.forEach((c)=>logger_logger.verbose(chalk_source.gray(` ${c.path}`)));
|
|
47918
47996
|
}
|
|
47919
47997
|
}
|
|
47920
|
-
async function deleteFilesRemovedOnAnvil(gitService, unstagedFiles) {
|
|
47998
|
+
async function deleteFilesRemovedOnAnvil(gitService, unstagedFiles, remotelyChangedFiles) {
|
|
47921
47999
|
const filesToRemove = [];
|
|
47922
|
-
for (const file of unstagedFiles)try {
|
|
48000
|
+
for (const file of unstagedFiles)if (remotelyChangedFiles.has(file)) try {
|
|
47923
48001
|
await gitService.show(`HEAD:${file}`);
|
|
47924
48002
|
} catch (e) {
|
|
47925
48003
|
filesToRemove.push(file);
|
|
@@ -49497,21 +49575,24 @@ var __webpack_exports__ = {};
|
|
|
49497
49575
|
const httpUrl = getGitFetchUrl(this.config.appId, this.config.getAuthToken(), this.config.anvilUrl);
|
|
49498
49576
|
const currentBranch = this.config.getCurrentBranch();
|
|
49499
49577
|
const tempRef = `anvil-sync-temp-${Date.now()}`;
|
|
49578
|
+
const oldCommitId = this.config.getCommitId();
|
|
49500
49579
|
await this.config.gitService.fetch(httpUrl, `+${currentBranch}:${tempRef}`);
|
|
49501
49580
|
await this.config.gitService.reset(tempRef, "mixed");
|
|
49502
49581
|
await this.config.gitService.deleteRef(`refs/heads/${tempRef}`);
|
|
49582
|
+
const newCommitId = await this.config.gitService.getCommitId();
|
|
49503
49583
|
await this.config.gitService.checkout([
|
|
49504
49584
|
".anvil_editor.yaml",
|
|
49505
49585
|
"anvil.yaml"
|
|
49506
49586
|
]);
|
|
49507
49587
|
await this.config.editorYaml.reload();
|
|
49508
|
-
await this.deleteFilesRemovedOnAnvilLocally();
|
|
49588
|
+
await this.deleteFilesRemovedOnAnvilLocally(oldCommitId, newCommitId);
|
|
49509
49589
|
await this.discardFormattingOnlyYamlChanges();
|
|
49510
49590
|
}
|
|
49511
|
-
async deleteFilesRemovedOnAnvilLocally() {
|
|
49591
|
+
async deleteFilesRemovedOnAnvilLocally(oldCommitId, newCommitId) {
|
|
49512
49592
|
try {
|
|
49513
49593
|
const status = await this.config.gitService.getStatus();
|
|
49514
|
-
await
|
|
49594
|
+
const remotelyChangedFiles = await detectRemoteChanges(this.config.gitService, oldCommitId, newCommitId);
|
|
49595
|
+
await deleteFilesRemovedOnAnvil(this.config.gitService, status.notAdded, remotelyChangedFiles);
|
|
49515
49596
|
} catch (e) {
|
|
49516
49597
|
logger_logger.verbose(chalk_source.gray(` Failed to check git status: ${errors_getErrorMessage(e)}`));
|
|
49517
49598
|
}
|
|
@@ -51571,15 +51652,16 @@ var __webpack_exports__ = {};
|
|
|
51571
51652
|
}
|
|
51572
51653
|
}
|
|
51573
51654
|
function registerWatchCommand(program) {
|
|
51574
|
-
const watchCommand = program.command("watch [path]").description("Watch for file changes and sync to Anvil").alias("sync").alias("w").option("-A, --appid <APP_ID>", "Specify app ID directly").option("-f, --first", "Auto-select first detected app ID without confirmation").option("-s, --staged-only", "Only sync staged changes (use git add to stage files)").option("-a, --auto", "Auto mode: restart on branch changes and sync when behind").option("-
|
|
51575
|
-
|
|
51655
|
+
const watchCommand = program.command("watch [path]").description("Watch for file changes and sync to Anvil").alias("sync").alias("w").option("-A, --appid <APP_ID>", "Specify app ID directly").option("-f, --first", "Auto-select first detected app ID without confirmation").option("-s, --staged-only", "Only sync staged changes (use git add to stage files)").option("-a, --auto", "Auto mode: restart on branch changes and sync when behind").option("-O, --open", "Open watched path in preferred editor (or default app)").option("-u, --url <ANVIL_URL>", "Specify Anvil server URL (e.g., anvil.works, localhost)").option("-U, --user <USERNAME>", "Specify which user account to use").action(async (path, options, command)=>{
|
|
51656
|
+
const globalOptions = command.optsWithGlobals();
|
|
51657
|
+
if (void 0 !== globalOptions.verbose && logger_logger instanceof CLILogger) logger_logger.setVerbose(globalOptions.verbose);
|
|
51576
51658
|
await handleWatchCommand({
|
|
51577
51659
|
path,
|
|
51578
51660
|
appid: options.appid,
|
|
51579
51661
|
useFirst: options.first,
|
|
51580
51662
|
stagedOnly: options.stagedOnly,
|
|
51581
51663
|
autoMode: options.auto,
|
|
51582
|
-
verbose:
|
|
51664
|
+
verbose: globalOptions.verbose,
|
|
51583
51665
|
open: options.open,
|
|
51584
51666
|
url: options.url,
|
|
51585
51667
|
user: options.user
|
|
@@ -52507,8 +52589,9 @@ var __webpack_exports__ = {};
|
|
|
52507
52589
|
await openPathInEditorOrDefault(destinationPath, preferredEditorCommand, deps);
|
|
52508
52590
|
}
|
|
52509
52591
|
function registerCheckoutCommand(program) {
|
|
52510
|
-
const checkoutCommand = program.command("checkout [input] [directory]").description("Check out an Anvil app locally from editor URL, git URL, app ID, or interactive selection").alias("co").option("-O, --open", "Open destination after checkout").option("-b, --branch <BRANCH>", "Checkout a specific branch").option("--depth <N>", "Create a shallow clone with history truncated to N commits", (value)=>parseInt(value, 10)).option("--single-branch", "Clone only one branch").option("--origin <NAME>", "Use a custom remote name instead of origin").option("--quiet", "Suppress git clone progress output").option("--verbose", "Enable verbose git clone output").option("-u, --url <ANVIL_URL>", "Specify Anvil server URL").option("-U, --user <USERNAME>", "Specify which user account to use").option("-f, --force", "Override safety checks for destination path").option("-Q, --query <QUERY>", "Initial search query for interactive checkout picker").action(async (input, directory, options)=>{
|
|
52592
|
+
const checkoutCommand = program.command("checkout [input] [directory]").description("Check out an Anvil app locally from editor URL, git URL, app ID, or interactive selection").alias("co").option("-O, --open", "Open destination after checkout").option("-b, --branch <BRANCH>", "Checkout a specific branch").option("--depth <N>", "Create a shallow clone with history truncated to N commits", (value)=>parseInt(value, 10)).option("--single-branch", "Clone only one branch").option("--origin <NAME>", "Use a custom remote name instead of origin").option("--quiet", "Suppress git clone progress output").option("--verbose", "Enable verbose git clone output").option("-u, --url <ANVIL_URL>", "Specify Anvil server URL").option("-U, --user <USERNAME>", "Specify which user account to use").option("-f, --force", "Override safety checks for destination path").option("-Q, --query <QUERY>", "Initial search query for interactive checkout picker").action(async (input, directory, options, command)=>{
|
|
52511
52593
|
try {
|
|
52594
|
+
const globalOptions = command?.optsWithGlobals() || options || {};
|
|
52512
52595
|
if ("number" == typeof options?.depth && (!Number.isFinite(options.depth) || options.depth <= 0)) throw new Error("--depth must be a positive integer");
|
|
52513
52596
|
await executeCheckout({
|
|
52514
52597
|
input,
|
|
@@ -52519,7 +52602,7 @@ var __webpack_exports__ = {};
|
|
|
52519
52602
|
singleBranch: options?.singleBranch,
|
|
52520
52603
|
origin: options?.origin,
|
|
52521
52604
|
quiet: options?.quiet,
|
|
52522
|
-
verbose:
|
|
52605
|
+
verbose: globalOptions.verbose,
|
|
52523
52606
|
url: options?.url,
|
|
52524
52607
|
user: options?.user,
|
|
52525
52608
|
force: options?.force,
|
|
@@ -52987,39 +53070,51 @@ var __webpack_exports__ = {};
|
|
|
52987
53070
|
process.exit(1);
|
|
52988
53071
|
}
|
|
52989
53072
|
}
|
|
52990
|
-
|
|
52991
|
-
|
|
52992
|
-
|
|
52993
|
-
|
|
52994
|
-
|
|
52995
|
-
|
|
52996
|
-
|
|
52997
|
-
const
|
|
52998
|
-
|
|
52999
|
-
|
|
53000
|
-
|
|
53001
|
-
|
|
53002
|
-
|
|
53003
|
-
|
|
53004
|
-
|
|
53005
|
-
|
|
53006
|
-
|
|
53007
|
-
|
|
53008
|
-
|
|
53009
|
-
|
|
53010
|
-
|
|
53011
|
-
|
|
53012
|
-
|
|
53013
|
-
|
|
53014
|
-
|
|
53015
|
-
|
|
53016
|
-
|
|
53017
|
-
})
|
|
53018
|
-
if (
|
|
53019
|
-
|
|
53020
|
-
|
|
53073
|
+
function addGlobalOptionsHelp(command) {
|
|
53074
|
+
if ("help" !== command.name()) command.addHelpText("after", "\n" + chalk_source.bold("Global Options:") + "\n -V, --verbose Show detailed output\n");
|
|
53075
|
+
command.commands.forEach((subcommand)=>addGlobalOptionsHelp(subcommand));
|
|
53076
|
+
}
|
|
53077
|
+
function buildProgram() {
|
|
53078
|
+
const program = new Command();
|
|
53079
|
+
program.name("anvil").description("CLI tool for developing Anvil apps locally").version(VERSION, "-v, --version", "Output the version number").option("--json", "Output in JSON format (NDJSON) for scripting/LLM consumption").option("-V, --verbose", "Show detailed output").helpOption('-h, --help', 'Display help for anvil command').hook("preAction", async (_thisCommand, actionCommand)=>{
|
|
53080
|
+
const opts = actionCommand.optsWithGlobals();
|
|
53081
|
+
setGlobalOutputConfig({
|
|
53082
|
+
jsonMode: !!opts.json
|
|
53083
|
+
});
|
|
53084
|
+
if (logger_logger instanceof CLILogger) logger_logger.setVerbose(!!opts.verbose);
|
|
53085
|
+
if (!opts.json) {
|
|
53086
|
+
const commandName = actionCommand?.name();
|
|
53087
|
+
if ("update" !== commandName && "git-credential" !== commandName) checkVersionAndWarn();
|
|
53088
|
+
}
|
|
53089
|
+
});
|
|
53090
|
+
const watchCommand = registerWatchCommand(program);
|
|
53091
|
+
registerCheckoutCommand(program);
|
|
53092
|
+
registerGitCredentialCommand(program);
|
|
53093
|
+
registerLoginCommand(program);
|
|
53094
|
+
registerLogoutCommand(program);
|
|
53095
|
+
registerConfigCommand(program);
|
|
53096
|
+
registerVersionCommand(program, VERSION);
|
|
53097
|
+
registerConfigureCommand(program, VERSION);
|
|
53098
|
+
program.command("update").description("Update anvil to the latest version").alias("u").action(async ()=>{
|
|
53099
|
+
await handleUpdateCommand();
|
|
53100
|
+
});
|
|
53101
|
+
if (watchCommand) {
|
|
53102
|
+
const watchOptions = watchCommand.options.map((opt)=>{
|
|
53103
|
+
const flags = opt.flags;
|
|
53104
|
+
const description = opt.description || "";
|
|
53105
|
+
return ` ${flags.padEnd(30)} ${description}`;
|
|
53106
|
+
}).join("\n");
|
|
53107
|
+
if (watchOptions) program.addHelpText("after", "\n" + chalk_source.bold("Watch Command Options:") + "\n" + chalk_source.gray(" (These options apply to the 'watch' command)") + "\n" + watchOptions + "\n");
|
|
53108
|
+
}
|
|
53109
|
+
program.commands.forEach((command)=>addGlobalOptionsHelp(command));
|
|
53110
|
+
return program;
|
|
53111
|
+
}
|
|
53112
|
+
buildProgram().parse();
|
|
53021
53113
|
})();
|
|
53022
|
-
|
|
53114
|
+
exports.buildProgram = __webpack_exports__.buildProgram;
|
|
53115
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
53116
|
+
"buildProgram"
|
|
53117
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
53023
53118
|
Object.defineProperty(exports, '__esModule', {
|
|
53024
53119
|
value: true
|
|
53025
53120
|
});
|
package/dist/index.js
CHANGED
|
@@ -22643,12 +22643,14 @@ var __webpack_exports__ = {};
|
|
|
22643
22643
|
editSession;
|
|
22644
22644
|
username;
|
|
22645
22645
|
reconnectAttempts = 0;
|
|
22646
|
+
connectAttempts = 0;
|
|
22646
22647
|
reconnectTimer = null;
|
|
22647
22648
|
heartbeatTimer = null;
|
|
22648
22649
|
pongTimeoutTimer = null;
|
|
22649
22650
|
reconnectDelayMs;
|
|
22650
22651
|
isClosing = false;
|
|
22651
22652
|
sessionId;
|
|
22653
|
+
lastDisconnectSummary = null;
|
|
22652
22654
|
RECONNECT_DELAY_BASE_MS = 5000;
|
|
22653
22655
|
RECONNECT_DELAY_MAX_MS = 60000;
|
|
22654
22656
|
HEARTBEAT_INTERVAL_MS = 30000;
|
|
@@ -22666,6 +22668,7 @@ var __webpack_exports__ = {};
|
|
|
22666
22668
|
}
|
|
22667
22669
|
async connect() {
|
|
22668
22670
|
this.isClosing = false;
|
|
22671
|
+
this.connectAttempts++;
|
|
22669
22672
|
if (this.ws?.readyState === ws_wrapper.OPEN) return void logger_logger.debug(`[WebSocket ${this.sessionId}]`, "WebSocket already open, skipping connection");
|
|
22670
22673
|
if (this.ws) {
|
|
22671
22674
|
logger_logger.debug(`[WebSocket ${this.sessionId}]`, "Closing existing WebSocket before reconnecting");
|
|
@@ -22674,6 +22677,7 @@ var __webpack_exports__ = {};
|
|
|
22674
22677
|
this.authToken = await auth_getValidAuthToken(this.anvilUrl, this.username);
|
|
22675
22678
|
const wsUrl = getWebSocketUrl(this.appId, this.authToken, this.anvilUrl);
|
|
22676
22679
|
logger_logger.debug(`[WebSocket ${this.sessionId}]`, `Connecting to: ${wsUrl.replace(this.authToken, "[TOKEN]")}`);
|
|
22680
|
+
logger_logger.verbose(chalk_source.gray(`WebSocket connecting to ${this.getConnectionTarget(wsUrl)} (app ${this.appId}, branch ${this.currentBranch}, session ${this.sessionId}, connect attempt ${this.connectAttempts})`));
|
|
22677
22681
|
this.ws = new ws_wrapper(wsUrl);
|
|
22678
22682
|
this.ws.on("open", ()=>{
|
|
22679
22683
|
logger_logger.verbose(chalk_source.green("🔌 Connected to Anvil WebSocket"));
|
|
@@ -22690,6 +22694,21 @@ var __webpack_exports__ = {};
|
|
|
22690
22694
|
this.ws?.send(JSON.stringify(subscribeMsg));
|
|
22691
22695
|
this.emit("connected", void 0);
|
|
22692
22696
|
});
|
|
22697
|
+
this.ws.on("unexpected-response", (request, response)=>{
|
|
22698
|
+
const summary = this.summarizeUnexpectedResponse(response, wsUrl);
|
|
22699
|
+
this.lastDisconnectSummary = summary;
|
|
22700
|
+
logger_logger.error(chalk_source.red(summary));
|
|
22701
|
+
response.resume();
|
|
22702
|
+
request.destroy();
|
|
22703
|
+
if (this.isClosing) return;
|
|
22704
|
+
this.stopHeartbeat();
|
|
22705
|
+
this.ws = null;
|
|
22706
|
+
this.emit("disconnected", {
|
|
22707
|
+
code: 1006,
|
|
22708
|
+
reason: summary
|
|
22709
|
+
});
|
|
22710
|
+
this.scheduleReconnect();
|
|
22711
|
+
});
|
|
22693
22712
|
this.ws.on("message", (data)=>{
|
|
22694
22713
|
this.markSocketResponsive();
|
|
22695
22714
|
try {
|
|
@@ -22714,6 +22733,7 @@ var __webpack_exports__ = {};
|
|
|
22714
22733
|
return;
|
|
22715
22734
|
}
|
|
22716
22735
|
if (this.isClosing) return;
|
|
22736
|
+
this.lastDisconnectSummary = this.lastDisconnectSummary ?? this.formatCloseSummary(code, reason.toString());
|
|
22717
22737
|
this.emit("disconnected", {
|
|
22718
22738
|
code,
|
|
22719
22739
|
reason: reason.toString()
|
|
@@ -22723,8 +22743,13 @@ var __webpack_exports__ = {};
|
|
|
22723
22743
|
this.ws.on("error", (error)=>{
|
|
22724
22744
|
logger_logger.debug(`[WebSocket ${this.sessionId}]`, `Error: ${error.message}`);
|
|
22725
22745
|
if (this.isClosing) return;
|
|
22726
|
-
if (error.message.includes("
|
|
22727
|
-
|
|
22746
|
+
if (error.message.includes("Unexpected server response")) return;
|
|
22747
|
+
if (error.message.includes("502")) logger_logger.error(chalk_source.red(`WebSocket connection failed (502 Bad Gateway) - the server could not open the live update connection (${this.getConnectionContext()})`));
|
|
22748
|
+
else {
|
|
22749
|
+
const details = this.getConnectionContext();
|
|
22750
|
+
logger_logger.error(chalk_source.red(`WebSocket error: ${error.message} (${details})`));
|
|
22751
|
+
}
|
|
22752
|
+
this.lastDisconnectSummary = `WebSocket error: ${error.message}`;
|
|
22728
22753
|
this.emit("error", {
|
|
22729
22754
|
error
|
|
22730
22755
|
});
|
|
@@ -22779,7 +22804,7 @@ var __webpack_exports__ = {};
|
|
|
22779
22804
|
if (this.reconnectTimer || this.isClosing) return;
|
|
22780
22805
|
this.reconnectAttempts++;
|
|
22781
22806
|
const delayMs = this.reconnectDelayMs;
|
|
22782
|
-
logger_logger.verbose(chalk_source.gray(`WebSocket disconnected, reconnecting in ${Math.round(delayMs / 1000)}s (attempt ${this.
|
|
22807
|
+
logger_logger.verbose(chalk_source.gray(`WebSocket disconnected (${this.lastDisconnectSummary ?? "unknown cause"}), reconnecting in ${Math.round(delayMs / 1000)}s (${this.getConnectionContext()}, next connect attempt ${this.connectAttempts + 1})...`));
|
|
22783
22808
|
this.reconnectTimer = setTimeout(()=>{
|
|
22784
22809
|
this.reconnectTimer = null;
|
|
22785
22810
|
this.connect().catch((error)=>{
|
|
@@ -22788,8 +22813,47 @@ var __webpack_exports__ = {};
|
|
|
22788
22813
|
});
|
|
22789
22814
|
});
|
|
22790
22815
|
}, delayMs);
|
|
22816
|
+
this.lastDisconnectSummary = null;
|
|
22791
22817
|
this.reconnectDelayMs = Math.min(Math.round(1.5 * this.reconnectDelayMs), this.RECONNECT_DELAY_MAX_MS);
|
|
22792
22818
|
}
|
|
22819
|
+
getConnectionContext() {
|
|
22820
|
+
return `app ${this.appId}, branch ${this.currentBranch}, session ${this.sessionId}`;
|
|
22821
|
+
}
|
|
22822
|
+
getConnectionTarget(wsUrl) {
|
|
22823
|
+
const url = new URL(wsUrl);
|
|
22824
|
+
return `${url.origin}${url.pathname}`;
|
|
22825
|
+
}
|
|
22826
|
+
formatCloseSummary(code, reason) {
|
|
22827
|
+
const suffix = reason ? `, reason=${reason}` : "";
|
|
22828
|
+
return `close code=${code}${suffix}`;
|
|
22829
|
+
}
|
|
22830
|
+
summarizeUnexpectedResponse(response, wsUrl) {
|
|
22831
|
+
const statusCode = response.statusCode ?? "unknown";
|
|
22832
|
+
const statusMessage = response.statusMessage ?? "Unknown";
|
|
22833
|
+
const details = [
|
|
22834
|
+
`target ${this.getConnectionTarget(wsUrl)}`,
|
|
22835
|
+
this.getConnectionContext(),
|
|
22836
|
+
this.getHandshakeMetadata(response)
|
|
22837
|
+
].filter(Boolean).join(", ");
|
|
22838
|
+
return `WebSocket handshake failed (${statusCode} ${statusMessage}; ${details})`;
|
|
22839
|
+
}
|
|
22840
|
+
getHandshakeMetadata(response) {
|
|
22841
|
+
const headers = response.headers;
|
|
22842
|
+
const detailParts = [];
|
|
22843
|
+
const requestId = this.getHeaderValue(headers["x-request-id"]) || this.getHeaderValue(headers["x-amzn-requestid"]) || this.getHeaderValue(headers["cf-ray"]);
|
|
22844
|
+
const retryAfter = this.getHeaderValue(headers["retry-after"]);
|
|
22845
|
+
const server = this.getHeaderValue(headers["server"]);
|
|
22846
|
+
const via = this.getHeaderValue(headers["via"]);
|
|
22847
|
+
if (requestId) detailParts.push(`request-id ${requestId}`);
|
|
22848
|
+
if (retryAfter) detailParts.push(`retry-after ${retryAfter}`);
|
|
22849
|
+
if (server) detailParts.push(`server ${server}`);
|
|
22850
|
+
if (via) detailParts.push(`via ${via}`);
|
|
22851
|
+
return detailParts.join(", ");
|
|
22852
|
+
}
|
|
22853
|
+
getHeaderValue(header) {
|
|
22854
|
+
if (Array.isArray(header)) return header[0] ?? null;
|
|
22855
|
+
return header ?? null;
|
|
22856
|
+
}
|
|
22793
22857
|
startHeartbeat() {
|
|
22794
22858
|
this.stopHeartbeat();
|
|
22795
22859
|
this.heartbeatTimer = setInterval(()=>{
|
|
@@ -22931,9 +22995,9 @@ var __webpack_exports__ = {};
|
|
|
22931
22995
|
result.localOnlyChanges.forEach((c)=>logger_logger.verbose(chalk_source.gray(` ${c.path}`)));
|
|
22932
22996
|
}
|
|
22933
22997
|
}
|
|
22934
|
-
async function deleteFilesRemovedOnAnvil(gitService, unstagedFiles) {
|
|
22998
|
+
async function deleteFilesRemovedOnAnvil(gitService, unstagedFiles, remotelyChangedFiles) {
|
|
22935
22999
|
const filesToRemove = [];
|
|
22936
|
-
for (const file of unstagedFiles)try {
|
|
23000
|
+
for (const file of unstagedFiles)if (remotelyChangedFiles.has(file)) try {
|
|
22937
23001
|
await gitService.show(`HEAD:${file}`);
|
|
22938
23002
|
} catch (e) {
|
|
22939
23003
|
filesToRemove.push(file);
|
|
@@ -25010,21 +25074,24 @@ var __webpack_exports__ = {};
|
|
|
25010
25074
|
const httpUrl = getGitFetchUrl(this.config.appId, this.config.getAuthToken(), this.config.anvilUrl);
|
|
25011
25075
|
const currentBranch = this.config.getCurrentBranch();
|
|
25012
25076
|
const tempRef = `anvil-sync-temp-${Date.now()}`;
|
|
25077
|
+
const oldCommitId = this.config.getCommitId();
|
|
25013
25078
|
await this.config.gitService.fetch(httpUrl, `+${currentBranch}:${tempRef}`);
|
|
25014
25079
|
await this.config.gitService.reset(tempRef, "mixed");
|
|
25015
25080
|
await this.config.gitService.deleteRef(`refs/heads/${tempRef}`);
|
|
25081
|
+
const newCommitId = await this.config.gitService.getCommitId();
|
|
25016
25082
|
await this.config.gitService.checkout([
|
|
25017
25083
|
".anvil_editor.yaml",
|
|
25018
25084
|
"anvil.yaml"
|
|
25019
25085
|
]);
|
|
25020
25086
|
await this.config.editorYaml.reload();
|
|
25021
|
-
await this.deleteFilesRemovedOnAnvilLocally();
|
|
25087
|
+
await this.deleteFilesRemovedOnAnvilLocally(oldCommitId, newCommitId);
|
|
25022
25088
|
await this.discardFormattingOnlyYamlChanges();
|
|
25023
25089
|
}
|
|
25024
|
-
async deleteFilesRemovedOnAnvilLocally() {
|
|
25090
|
+
async deleteFilesRemovedOnAnvilLocally(oldCommitId, newCommitId) {
|
|
25025
25091
|
try {
|
|
25026
25092
|
const status = await this.config.gitService.getStatus();
|
|
25027
|
-
await
|
|
25093
|
+
const remotelyChangedFiles = await detectRemoteChanges(this.config.gitService, oldCommitId, newCommitId);
|
|
25094
|
+
await deleteFilesRemovedOnAnvil(this.config.gitService, status.notAdded, remotelyChangedFiles);
|
|
25028
25095
|
} catch (e) {
|
|
25029
25096
|
logger_logger.verbose(chalk_source.gray(` Failed to check git status: ${errors_getErrorMessage(e)}`));
|
|
25030
25097
|
}
|