@anvil-works/anvil-cli 0.6.3 → 0.7.0-canary.1
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/CLILogger.d.ts +4 -4
- package/dist/CLILogger.d.ts.map +1 -1
- package/dist/SavePathRouter.d.ts +11 -1
- package/dist/SavePathRouter.d.ts.map +1 -1
- package/dist/api.d.ts +18 -7
- package/dist/api.d.ts.map +1 -1
- package/dist/cli.js +322 -130
- package/dist/commands/checkout.d.ts +10 -11
- package/dist/commands/checkout.d.ts.map +1 -1
- package/dist/commands/configure.d.ts.map +1 -1
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/globalConfig.d.ts +6 -0
- package/dist/globalConfig.d.ts.map +1 -1
- package/dist/index.js +258 -1542
- package/dist/logger.d.ts +7 -3
- package/dist/logger.d.ts.map +1 -1
- package/dist/services/auth.d.ts +2 -1
- package/dist/services/auth.d.ts.map +1 -1
- package/dist/services/oauth-login.d.ts.map +1 -1
- package/dist/services/token-store.d.ts +2 -0
- package/dist/services/token-store.d.ts.map +1 -1
- package/dist/services/validation.d.ts +6 -1
- package/dist/services/validation.d.ts.map +1 -1
- package/dist/watch/SaveProcessor.d.ts.map +1 -1
- package/package.json +3 -2
package/dist/cli.js
CHANGED
|
@@ -42250,12 +42250,13 @@ var __webpack_exports__ = {};
|
|
|
42250
42250
|
const EMPTY_TOKENS = {
|
|
42251
42251
|
authToken: null,
|
|
42252
42252
|
refreshToken: null,
|
|
42253
|
-
authTokenExpiresAt: null
|
|
42253
|
+
authTokenExpiresAt: null,
|
|
42254
|
+
clientId: null
|
|
42254
42255
|
};
|
|
42255
42256
|
function isAccountTokens(value) {
|
|
42256
42257
|
if (!value || "object" != typeof value || Array.isArray(value)) return false;
|
|
42257
42258
|
const obj = value;
|
|
42258
|
-
return ("authToken" in obj || "refreshToken" in obj || "authTokenExpiresAt" in obj) && (null === obj.authToken || "string" == typeof obj.authToken) && (null === obj.refreshToken || "string" == typeof obj.refreshToken) && (null === obj.authTokenExpiresAt || "number" == typeof obj.authTokenExpiresAt);
|
|
42259
|
+
return ("authToken" in obj || "refreshToken" in obj || "authTokenExpiresAt" in obj) && (null === obj.authToken || "string" == typeof obj.authToken) && (null === obj.refreshToken || "string" == typeof obj.refreshToken) && (null === obj.authTokenExpiresAt || "number" == typeof obj.authTokenExpiresAt) && (!("clientId" in obj) || null === obj.clientId || "string" == typeof obj.clientId);
|
|
42259
42260
|
}
|
|
42260
42261
|
function isUrlTokens(value) {
|
|
42261
42262
|
if (!value || "object" != typeof value || Array.isArray(value)) return false;
|
|
@@ -42319,7 +42320,8 @@ var __webpack_exports__ = {};
|
|
|
42319
42320
|
if (keychainOk) store[normalized][username] = {
|
|
42320
42321
|
authToken: null,
|
|
42321
42322
|
refreshToken: null,
|
|
42322
|
-
authTokenExpiresAt: tokens.authTokenExpiresAt
|
|
42323
|
+
authTokenExpiresAt: tokens.authTokenExpiresAt,
|
|
42324
|
+
clientId: tokens.clientId ?? null
|
|
42323
42325
|
};
|
|
42324
42326
|
else store[normalized][username] = tokens;
|
|
42325
42327
|
setTokenStore(store);
|
|
@@ -42600,6 +42602,10 @@ var __webpack_exports__ = {};
|
|
|
42600
42602
|
function getGlobalOutputConfig() {
|
|
42601
42603
|
return globalOutputConfig;
|
|
42602
42604
|
}
|
|
42605
|
+
function assertCanPrompt(action = "This command", explicitAlternative = "Pass explicit flags instead.") {
|
|
42606
|
+
if (globalOutputConfig.jsonMode) throw new Error(`${action} requires interactive input, but --json disables prompts. ${explicitAlternative}`);
|
|
42607
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) throw new Error(`${action} requires interactive input, but stdin/stdout is not a TTY. ${explicitAlternative}`);
|
|
42608
|
+
}
|
|
42603
42609
|
const logger_timestamp = ()=>new Date().toISOString();
|
|
42604
42610
|
const verboseTimestamp = ()=>{
|
|
42605
42611
|
const now = new Date();
|
|
@@ -42706,14 +42712,32 @@ var __webpack_exports__ = {};
|
|
|
42706
42712
|
resume() {
|
|
42707
42713
|
this.paused = false;
|
|
42708
42714
|
}
|
|
42709
|
-
async prompt(questions) {
|
|
42715
|
+
async prompt(questions, options) {
|
|
42716
|
+
assertCanPrompt(options?.action ?? "Prompt", options?.nonInteractiveHint);
|
|
42710
42717
|
throw new Error("Prompting not supported in DefaultLogger. Use CLILogger for interactive prompts.");
|
|
42711
42718
|
}
|
|
42712
|
-
async confirm(message, defaultValue = true) {
|
|
42713
|
-
|
|
42719
|
+
async confirm(message, defaultValue = true, options) {
|
|
42720
|
+
const answer = await this.prompt([
|
|
42721
|
+
{
|
|
42722
|
+
type: "confirm",
|
|
42723
|
+
name: "value",
|
|
42724
|
+
message,
|
|
42725
|
+
default: defaultValue
|
|
42726
|
+
}
|
|
42727
|
+
], options);
|
|
42728
|
+
return answer.value;
|
|
42714
42729
|
}
|
|
42715
|
-
async select(message, choices, defaultValue) {
|
|
42716
|
-
|
|
42730
|
+
async select(message, choices, defaultValue, options) {
|
|
42731
|
+
const answer = await this.prompt([
|
|
42732
|
+
{
|
|
42733
|
+
type: "list",
|
|
42734
|
+
name: "value",
|
|
42735
|
+
message,
|
|
42736
|
+
choices,
|
|
42737
|
+
default: defaultValue
|
|
42738
|
+
}
|
|
42739
|
+
], options);
|
|
42740
|
+
return answer.value;
|
|
42717
42741
|
}
|
|
42718
42742
|
}
|
|
42719
42743
|
let logger_logger = new DefaultLogger();
|
|
@@ -42854,7 +42878,8 @@ var __webpack_exports__ = {};
|
|
|
42854
42878
|
setVerbose(value) {
|
|
42855
42879
|
this.sessionVerbose = value;
|
|
42856
42880
|
}
|
|
42857
|
-
async prompt(questions) {
|
|
42881
|
+
async prompt(questions, options) {
|
|
42882
|
+
assertCanPrompt(options?.action ?? "Prompt", options?.nonInteractiveHint);
|
|
42858
42883
|
this.pause();
|
|
42859
42884
|
try {
|
|
42860
42885
|
return await inquirer_dist_esm.prompt(questions);
|
|
@@ -42862,7 +42887,7 @@ var __webpack_exports__ = {};
|
|
|
42862
42887
|
this.resume();
|
|
42863
42888
|
}
|
|
42864
42889
|
}
|
|
42865
|
-
async confirm(message, defaultValue = true) {
|
|
42890
|
+
async confirm(message, defaultValue = true, options) {
|
|
42866
42891
|
const answer = await this.prompt([
|
|
42867
42892
|
{
|
|
42868
42893
|
type: "confirm",
|
|
@@ -42870,10 +42895,10 @@ var __webpack_exports__ = {};
|
|
|
42870
42895
|
message,
|
|
42871
42896
|
default: defaultValue
|
|
42872
42897
|
}
|
|
42873
|
-
]);
|
|
42898
|
+
], options);
|
|
42874
42899
|
return answer.value;
|
|
42875
42900
|
}
|
|
42876
|
-
async select(message, choices, defaultValue) {
|
|
42901
|
+
async select(message, choices, defaultValue, options) {
|
|
42877
42902
|
const answer = await this.prompt([
|
|
42878
42903
|
{
|
|
42879
42904
|
type: "list",
|
|
@@ -42883,7 +42908,7 @@ var __webpack_exports__ = {};
|
|
|
42883
42908
|
default: defaultValue,
|
|
42884
42909
|
loop: false
|
|
42885
42910
|
}
|
|
42886
|
-
]);
|
|
42911
|
+
], options);
|
|
42887
42912
|
return answer.value;
|
|
42888
42913
|
}
|
|
42889
42914
|
}
|
|
@@ -47243,6 +47268,7 @@ var __webpack_exports__ = {};
|
|
|
47243
47268
|
function getDefaultAnvilUrl() {
|
|
47244
47269
|
return resolveAnvilUrl();
|
|
47245
47270
|
}
|
|
47271
|
+
const ANVIL_SYNC_CLIENT_ID = "anvil-sync";
|
|
47246
47272
|
async function verifyAuth(authToken, anvilUrl = getDefaultAnvilUrl()) {
|
|
47247
47273
|
try {
|
|
47248
47274
|
const resp = await fetch(`${anvilUrl}/ide/api/_/user`, {
|
|
@@ -47262,7 +47288,7 @@ var __webpack_exports__ = {};
|
|
|
47262
47288
|
throw errors_createAuthError.invalid(`Network error: ${e.message}`);
|
|
47263
47289
|
}
|
|
47264
47290
|
}
|
|
47265
|
-
async function refreshAccessToken(refreshToken, anvilUrl = getDefaultAnvilUrl()) {
|
|
47291
|
+
async function refreshAccessToken(refreshToken, anvilUrl = getDefaultAnvilUrl(), clientId = ANVIL_SYNC_CLIENT_ID) {
|
|
47266
47292
|
try {
|
|
47267
47293
|
const tokenResponse = await fetch(`${anvilUrl}/oauth/token`, {
|
|
47268
47294
|
method: "POST",
|
|
@@ -47272,7 +47298,7 @@ var __webpack_exports__ = {};
|
|
|
47272
47298
|
body: new URLSearchParams({
|
|
47273
47299
|
grant_type: "refresh_token",
|
|
47274
47300
|
refresh_token: refreshToken,
|
|
47275
|
-
client_id:
|
|
47301
|
+
client_id: clientId
|
|
47276
47302
|
})
|
|
47277
47303
|
});
|
|
47278
47304
|
if (!tokenResponse.ok) {
|
|
@@ -47295,7 +47321,8 @@ var __webpack_exports__ = {};
|
|
|
47295
47321
|
if (!tokens.authToken && !tokens.refreshToken) throw errors_createAuthError.required("Not logged in. Please log in first.");
|
|
47296
47322
|
const isExpired = null !== tokens.authTokenExpiresAt && tokens.authTokenExpiresAt <= Math.floor(Date.now() / 1000) + 60;
|
|
47297
47323
|
if (tokens.refreshToken && isExpired) try {
|
|
47298
|
-
const
|
|
47324
|
+
const clientId = tokens.clientId ?? ANVIL_SYNC_CLIENT_ID;
|
|
47325
|
+
const tokenData = await refreshAccessToken(tokens.refreshToken, normalized, clientId);
|
|
47299
47326
|
const newExpiresAt = Math.floor(Date.now() / 1000) + tokenData.expires_in;
|
|
47300
47327
|
let accountUsername = username;
|
|
47301
47328
|
if (!accountUsername) {
|
|
@@ -47312,7 +47339,8 @@ var __webpack_exports__ = {};
|
|
|
47312
47339
|
setAccountTokens(normalized, accountUsername, {
|
|
47313
47340
|
authToken: tokenData.access_token,
|
|
47314
47341
|
refreshToken: tokenData.refresh_token,
|
|
47315
|
-
authTokenExpiresAt: newExpiresAt
|
|
47342
|
+
authTokenExpiresAt: newExpiresAt,
|
|
47343
|
+
clientId
|
|
47316
47344
|
});
|
|
47317
47345
|
return tokenData.access_token;
|
|
47318
47346
|
} catch (e) {
|
|
@@ -47337,7 +47365,8 @@ var __webpack_exports__ = {};
|
|
|
47337
47365
|
setAccountTokens(normalized, username, {
|
|
47338
47366
|
authToken: tokenData.access_token,
|
|
47339
47367
|
refreshToken: tokenData.refresh_token,
|
|
47340
|
-
authTokenExpiresAt: expiresAt
|
|
47368
|
+
authTokenExpiresAt: expiresAt,
|
|
47369
|
+
clientId: ANVIL_SYNC_CLIENT_ID
|
|
47341
47370
|
});
|
|
47342
47371
|
return {
|
|
47343
47372
|
success: true,
|
|
@@ -48731,7 +48760,9 @@ var __webpack_exports__ = {};
|
|
|
48731
48760
|
};
|
|
48732
48761
|
return null;
|
|
48733
48762
|
}
|
|
48734
|
-
async function loadFormTemplateData(
|
|
48763
|
+
async function loadFormTemplateData(relativePath, templateInfo, context) {
|
|
48764
|
+
const { repoPath, stagedOnly = false } = context;
|
|
48765
|
+
const { kind, format } = templateInfo;
|
|
48735
48766
|
try {
|
|
48736
48767
|
const content = await readFileContent(repoPath, relativePath, stagedOnly);
|
|
48737
48768
|
if ("yaml" === format) {
|
|
@@ -48819,7 +48850,8 @@ var __webpack_exports__ = {};
|
|
|
48819
48850
|
if (formTemplateInfo) return "forms";
|
|
48820
48851
|
return null;
|
|
48821
48852
|
}
|
|
48822
|
-
async function validateRename(fromPath, toPath,
|
|
48853
|
+
async function validateRename(fromPath, toPath, context) {
|
|
48854
|
+
const { repoPath, editorYaml } = context;
|
|
48823
48855
|
const fromEntityType = await getEntityTypeFromPath(repoPath, fromPath, editorYaml);
|
|
48824
48856
|
const toEntityType = await getEntityTypeFromPath(repoPath, toPath, editorYaml);
|
|
48825
48857
|
if (null === fromEntityType || null === toEntityType) return {
|
|
@@ -48977,7 +49009,8 @@ var __webpack_exports__ = {};
|
|
|
48977
49009
|
}
|
|
48978
49010
|
return filtered;
|
|
48979
49011
|
}
|
|
48980
|
-
async function routeFileChange(
|
|
49012
|
+
async function routeFileChange(change, context) {
|
|
49013
|
+
const { relativePath, changeType, fromPath } = change;
|
|
48981
49014
|
logger_logger.verbose(chalk_source.gray(`Routing ${changeType}: ${relativePath}${fromPath ? ` (from: ${fromPath})` : ""}`));
|
|
48982
49015
|
if (isGitRelatedFile(relativePath)) return {
|
|
48983
49016
|
type: "ignore",
|
|
@@ -48990,9 +49023,12 @@ var __webpack_exports__ = {};
|
|
|
48990
49023
|
type: "ignore",
|
|
48991
49024
|
reason: "Rename operation missing from path"
|
|
48992
49025
|
};
|
|
48993
|
-
return await handleRename(
|
|
49026
|
+
return await handleRename({
|
|
49027
|
+
fromPath,
|
|
49028
|
+
toPath: relativePath
|
|
49029
|
+
}, context);
|
|
48994
49030
|
}
|
|
48995
|
-
return await routeSavableChange(
|
|
49031
|
+
return await routeSavableChange(change, context);
|
|
48996
49032
|
}
|
|
48997
49033
|
function isGitRelatedFile(relativePath) {
|
|
48998
49034
|
return ".git" === relativePath || relativePath.startsWith(".git/") || relativePath.endsWith("/.git");
|
|
@@ -49011,47 +49047,60 @@ var __webpack_exports__ = {};
|
|
|
49011
49047
|
const parts = relativePath.split("/");
|
|
49012
49048
|
return 2 === parts.length;
|
|
49013
49049
|
},
|
|
49014
|
-
handle:
|
|
49050
|
+
handle: handleScriptsChange
|
|
49015
49051
|
},
|
|
49016
49052
|
{
|
|
49017
49053
|
matches: (relativePath)=>relativePath.startsWith("server_code/") && relativePath.endsWith(".py"),
|
|
49018
|
-
handle:
|
|
49054
|
+
handle: handleServerCodeChange
|
|
49019
49055
|
},
|
|
49020
49056
|
{
|
|
49021
49057
|
matches: (relativePath)=>relativePath.startsWith("client_code/") && relativePath.endsWith(".py"),
|
|
49022
|
-
handle:
|
|
49058
|
+
handle: handleClientCodeChange
|
|
49023
49059
|
},
|
|
49024
49060
|
{
|
|
49025
49061
|
matches: (relativePath)=>null !== detectFormTemplate(relativePath),
|
|
49026
|
-
handle:
|
|
49062
|
+
handle: handleFormTemplateChange
|
|
49027
49063
|
},
|
|
49028
49064
|
{
|
|
49029
49065
|
matches: (relativePath)=>"theme/parameters.yaml" === relativePath,
|
|
49030
|
-
handle:
|
|
49066
|
+
handle: handleThemeParametersChange
|
|
49031
49067
|
},
|
|
49032
49068
|
{
|
|
49033
49069
|
matches: (relativePath)=>relativePath.startsWith("theme/assets/"),
|
|
49034
|
-
handle:
|
|
49070
|
+
handle: handleAssetChange
|
|
49035
49071
|
},
|
|
49036
49072
|
{
|
|
49037
49073
|
matches: ()=>true,
|
|
49038
|
-
handle:
|
|
49074
|
+
handle: handleExtraFileChange
|
|
49039
49075
|
}
|
|
49040
49076
|
];
|
|
49041
|
-
async function handleRename(
|
|
49042
|
-
const
|
|
49077
|
+
async function handleRename(rename, context) {
|
|
49078
|
+
const { fromPath, toPath } = rename;
|
|
49079
|
+
const validation = await validateRename(fromPath, toPath, context);
|
|
49043
49080
|
if (!validation.valid) {
|
|
49044
49081
|
logger_logger.verbose(chalk_source.yellow(`Rename invalid (${validation.reason}), falling back to unlink + add`));
|
|
49045
|
-
const unlinkResult = await routeFileChange(
|
|
49046
|
-
|
|
49082
|
+
const unlinkResult = await routeFileChange({
|
|
49083
|
+
relativePath: fromPath,
|
|
49084
|
+
changeType: "unlink"
|
|
49085
|
+
}, context);
|
|
49086
|
+
const addResult = await routeFileChange({
|
|
49087
|
+
relativePath: toPath,
|
|
49088
|
+
changeType: "add"
|
|
49089
|
+
}, context);
|
|
49047
49090
|
return [
|
|
49048
49091
|
unlinkResult,
|
|
49049
49092
|
addResult
|
|
49050
49093
|
].flat();
|
|
49051
49094
|
}
|
|
49052
|
-
return await handleRenameOperation(
|
|
49095
|
+
return await handleRenameOperation({
|
|
49096
|
+
fromPath,
|
|
49097
|
+
toPath,
|
|
49098
|
+
entityType: validation.entityType
|
|
49099
|
+
}, context);
|
|
49053
49100
|
}
|
|
49054
|
-
async function handleRenameOperation(
|
|
49101
|
+
async function handleRenameOperation(rename, context) {
|
|
49102
|
+
const { repoPath, editorYaml, stagedOnly = false } = context;
|
|
49103
|
+
const { fromPath, toPath, entityType } = rename;
|
|
49055
49104
|
let oldName;
|
|
49056
49105
|
let newName;
|
|
49057
49106
|
let prefix = [];
|
|
@@ -49060,10 +49109,10 @@ var __webpack_exports__ = {};
|
|
|
49060
49109
|
let isPackage = false;
|
|
49061
49110
|
let actualToPath = toPath;
|
|
49062
49111
|
if ("scripts" === entityType) {
|
|
49063
|
-
const toRenameResult = await handlePathRenaming(
|
|
49112
|
+
const toRenameResult = await handlePathRenaming(toPath, "scripts", context);
|
|
49064
49113
|
if (toRenameResult.ignoreResult) return toRenameResult.ignoreResult;
|
|
49065
49114
|
actualToPath = toRenameResult.newRelativePath;
|
|
49066
|
-
const fromRenameResult = await handlePathRenaming(
|
|
49115
|
+
const fromRenameResult = await handlePathRenaming(fromPath, "scripts", context);
|
|
49067
49116
|
oldName = fromRenameResult.pythonifiedName;
|
|
49068
49117
|
newName = toRenameResult.pythonifiedName;
|
|
49069
49118
|
prefix = [
|
|
@@ -49075,10 +49124,10 @@ var __webpack_exports__ = {};
|
|
|
49075
49124
|
code
|
|
49076
49125
|
});
|
|
49077
49126
|
} else if ("server_modules" === entityType) {
|
|
49078
|
-
const toRenameResult = await handlePathRenaming(
|
|
49127
|
+
const toRenameResult = await handlePathRenaming(toPath, "server_code", context);
|
|
49079
49128
|
if (toRenameResult.ignoreResult) return toRenameResult.ignoreResult;
|
|
49080
49129
|
actualToPath = toRenameResult.newRelativePath;
|
|
49081
|
-
const fromRenameResult = await handlePathRenaming(
|
|
49130
|
+
const fromRenameResult = await handlePathRenaming(fromPath, "server_code", context);
|
|
49082
49131
|
oldName = fromRenameResult.pythonifiedName;
|
|
49083
49132
|
newName = toRenameResult.pythonifiedName;
|
|
49084
49133
|
prefix = [
|
|
@@ -49092,10 +49141,10 @@ var __webpack_exports__ = {};
|
|
|
49092
49141
|
is_package: isPackage
|
|
49093
49142
|
});
|
|
49094
49143
|
} else if ("modules" === entityType) {
|
|
49095
|
-
const toRenameResult = await handlePathRenaming(
|
|
49144
|
+
const toRenameResult = await handlePathRenaming(toPath, "client_code", context);
|
|
49096
49145
|
if (toRenameResult.ignoreResult) return toRenameResult.ignoreResult;
|
|
49097
49146
|
actualToPath = toRenameResult.newRelativePath;
|
|
49098
|
-
const fromRenameResult = await handlePathRenaming(
|
|
49147
|
+
const fromRenameResult = await handlePathRenaming(fromPath, "client_code", context);
|
|
49099
49148
|
oldName = fromRenameResult.pythonifiedName;
|
|
49100
49149
|
newName = toRenameResult.pythonifiedName;
|
|
49101
49150
|
isPackage = actualToPath.endsWith("__init__.py");
|
|
@@ -49113,10 +49162,10 @@ var __webpack_exports__ = {};
|
|
|
49113
49162
|
type: "ignore",
|
|
49114
49163
|
reason: "Form template rename to .yaml file is only supported when entire form is renamed"
|
|
49115
49164
|
};
|
|
49116
|
-
const toRenameResult = await handlePathRenaming(
|
|
49165
|
+
const toRenameResult = await handlePathRenaming(toPath, "client_code", context);
|
|
49117
49166
|
if (toRenameResult.ignoreResult) return toRenameResult.ignoreResult;
|
|
49118
49167
|
actualToPath = toRenameResult.newRelativePath;
|
|
49119
|
-
const fromRenameResult = await handlePathRenaming(
|
|
49168
|
+
const fromRenameResult = await handlePathRenaming(fromPath, "client_code", context);
|
|
49120
49169
|
oldName = fromRenameResult.pythonifiedName;
|
|
49121
49170
|
const isPackageInit = actualToPath.endsWith("__init__.py");
|
|
49122
49171
|
const kind = isPackageInit ? "package" : "module";
|
|
@@ -49125,7 +49174,10 @@ var __webpack_exports__ = {};
|
|
|
49125
49174
|
type: "ignore",
|
|
49126
49175
|
reason: "Form template not found for rename destination"
|
|
49127
49176
|
};
|
|
49128
|
-
const result = await buildFormTemplateData(
|
|
49177
|
+
const result = await buildFormTemplateData(templateInfo.relativePath, {
|
|
49178
|
+
kind,
|
|
49179
|
+
format: templateInfo.format
|
|
49180
|
+
}, context);
|
|
49129
49181
|
if (result.ignoreResult) return result.ignoreResult;
|
|
49130
49182
|
newName = result.className;
|
|
49131
49183
|
prefix = [
|
|
@@ -49173,7 +49225,9 @@ var __webpack_exports__ = {};
|
|
|
49173
49225
|
content: payload
|
|
49174
49226
|
};
|
|
49175
49227
|
}
|
|
49176
|
-
async function routeSavableChange(
|
|
49228
|
+
async function routeSavableChange(change, context) {
|
|
49229
|
+
const { repoPath, editorYaml, stagedOnly = false } = context;
|
|
49230
|
+
const { relativePath, changeType } = change;
|
|
49177
49231
|
if ("anvil.yaml" === relativePath) return {
|
|
49178
49232
|
type: "ignore",
|
|
49179
49233
|
reason: "anvil.yaml handled specially (multiple save paths)"
|
|
@@ -49217,13 +49271,15 @@ var __webpack_exports__ = {};
|
|
|
49217
49271
|
};
|
|
49218
49272
|
}
|
|
49219
49273
|
if ("unlink" === changeType) return await handleFileDeletion(repoPath, relativePath, editorYaml);
|
|
49220
|
-
for (const route of ROUTES)if (route.matches(relativePath)) return await route.handle(
|
|
49274
|
+
for (const route of ROUTES)if (route.matches(relativePath)) return await route.handle(change, context);
|
|
49221
49275
|
return {
|
|
49222
49276
|
type: "ignore",
|
|
49223
49277
|
reason: "Not a recognized Anvil file type"
|
|
49224
49278
|
};
|
|
49225
49279
|
}
|
|
49226
|
-
async function handleThemeParametersChange(
|
|
49280
|
+
async function handleThemeParametersChange(change, context) {
|
|
49281
|
+
const { repoPath, stagedOnly = false } = context;
|
|
49282
|
+
const { relativePath } = change;
|
|
49227
49283
|
const content = await readFileContent(repoPath, relativePath, stagedOnly);
|
|
49228
49284
|
const parametersData = jsYaml.load(content);
|
|
49229
49285
|
return {
|
|
@@ -49235,7 +49291,9 @@ var __webpack_exports__ = {};
|
|
|
49235
49291
|
content: parametersData
|
|
49236
49292
|
};
|
|
49237
49293
|
}
|
|
49238
|
-
async function handleExtraFileChange(
|
|
49294
|
+
async function handleExtraFileChange(change, context) {
|
|
49295
|
+
const { repoPath, stagedOnly = false } = context;
|
|
49296
|
+
const { relativePath } = change;
|
|
49239
49297
|
const content = await readBinaryFileContent(repoPath, relativePath, stagedOnly);
|
|
49240
49298
|
const base64Content = content.toString("base64");
|
|
49241
49299
|
const pathParts = [
|
|
@@ -49248,7 +49306,9 @@ var __webpack_exports__ = {};
|
|
|
49248
49306
|
content: base64Content
|
|
49249
49307
|
};
|
|
49250
49308
|
}
|
|
49251
|
-
async function handleDirectoryRenaming(
|
|
49309
|
+
async function handleDirectoryRenaming(rename, context) {
|
|
49310
|
+
const { repoPath } = context;
|
|
49311
|
+
const { originalParts, pythonifiedParts, baseDir } = rename;
|
|
49252
49312
|
const needsRename = originalParts.some((part, idx)=>part !== pythonifiedParts[idx]);
|
|
49253
49313
|
if (!needsRename) return null;
|
|
49254
49314
|
const needsDirRename = originalParts.slice(0, -1).some((part, idx)=>part !== pythonifiedParts[idx]);
|
|
@@ -49266,7 +49326,9 @@ var __webpack_exports__ = {};
|
|
|
49266
49326
|
}
|
|
49267
49327
|
return null;
|
|
49268
49328
|
}
|
|
49269
|
-
async function renameIfNeeded(
|
|
49329
|
+
async function renameIfNeeded(rename, context) {
|
|
49330
|
+
const { repoPath } = context;
|
|
49331
|
+
const { relativePath, originalNameOrParts, baseDir } = rename;
|
|
49270
49332
|
let pythonifiedName;
|
|
49271
49333
|
let pythonifiedParts;
|
|
49272
49334
|
let needsRename;
|
|
@@ -49304,8 +49366,10 @@ var __webpack_exports__ = {};
|
|
|
49304
49366
|
ignoreResult
|
|
49305
49367
|
};
|
|
49306
49368
|
}
|
|
49307
|
-
async function handleScriptsChange(
|
|
49308
|
-
const
|
|
49369
|
+
async function handleScriptsChange(change, context) {
|
|
49370
|
+
const { repoPath, editorYaml, stagedOnly = false } = context;
|
|
49371
|
+
const { relativePath, changeType } = change;
|
|
49372
|
+
const renameResult = await handlePathRenaming(relativePath, "scripts", context);
|
|
49309
49373
|
if (renameResult.ignoreResult) return renameResult.ignoreResult;
|
|
49310
49374
|
const actualPath = renameResult.newRelativePath;
|
|
49311
49375
|
const content = await readFileContent(repoPath, actualPath, stagedOnly);
|
|
@@ -49327,8 +49391,10 @@ var __webpack_exports__ = {};
|
|
|
49327
49391
|
]
|
|
49328
49392
|
});
|
|
49329
49393
|
}
|
|
49330
|
-
async function handleServerCodeChange(
|
|
49331
|
-
const
|
|
49394
|
+
async function handleServerCodeChange(change, context) {
|
|
49395
|
+
const { repoPath, editorYaml, stagedOnly = false } = context;
|
|
49396
|
+
const { relativePath, changeType } = change;
|
|
49397
|
+
const renameResult = await handlePathRenaming(relativePath, "server_code", context);
|
|
49332
49398
|
if (renameResult.ignoreResult) return renameResult.ignoreResult;
|
|
49333
49399
|
const actualPath = renameResult.newRelativePath;
|
|
49334
49400
|
const isPackage = actualPath.endsWith("__init__.py");
|
|
@@ -49353,8 +49419,10 @@ var __webpack_exports__ = {};
|
|
|
49353
49419
|
]
|
|
49354
49420
|
});
|
|
49355
49421
|
}
|
|
49356
|
-
async function handleClientCodeFormChange(
|
|
49357
|
-
const
|
|
49422
|
+
async function handleClientCodeFormChange(options, context) {
|
|
49423
|
+
const { editorYaml } = context;
|
|
49424
|
+
const { templatePath, templateInfo, changeType } = options;
|
|
49425
|
+
const result = await buildFormTemplateData(templatePath, templateInfo, context);
|
|
49358
49426
|
if (result.ignoreResult) return result.ignoreResult;
|
|
49359
49427
|
const { formData, className: extractedClassName } = result;
|
|
49360
49428
|
return handleIdBasedOperation({
|
|
@@ -49372,30 +49440,47 @@ var __webpack_exports__ = {};
|
|
|
49372
49440
|
]
|
|
49373
49441
|
});
|
|
49374
49442
|
}
|
|
49375
|
-
async function handlePathRenaming(
|
|
49443
|
+
async function handlePathRenaming(relativePath, baseDir, context) {
|
|
49376
49444
|
const parts = relativePath.slice(0, -3).split("/");
|
|
49377
49445
|
const originalParts = parts.slice(1);
|
|
49378
49446
|
const pythonifiedParts = originalParts.map(pythonifyName);
|
|
49379
49447
|
const pythonifiedName = extractPythonName(relativePath);
|
|
49380
|
-
const dirRenameResult = await handleDirectoryRenaming(
|
|
49448
|
+
const dirRenameResult = await handleDirectoryRenaming({
|
|
49449
|
+
originalParts,
|
|
49450
|
+
pythonifiedParts,
|
|
49451
|
+
baseDir
|
|
49452
|
+
}, context);
|
|
49381
49453
|
if (dirRenameResult) return {
|
|
49382
49454
|
pythonifiedName,
|
|
49383
49455
|
pythonifiedParts,
|
|
49384
49456
|
newRelativePath: relativePath,
|
|
49385
49457
|
ignoreResult: dirRenameResult
|
|
49386
49458
|
};
|
|
49387
|
-
const renameResult = await renameIfNeeded(
|
|
49459
|
+
const renameResult = await renameIfNeeded({
|
|
49460
|
+
relativePath,
|
|
49461
|
+
originalNameOrParts: originalParts,
|
|
49462
|
+
baseDir
|
|
49463
|
+
}, context);
|
|
49388
49464
|
return renameResult;
|
|
49389
49465
|
}
|
|
49390
|
-
async function handleClientCodeChange(
|
|
49391
|
-
const
|
|
49466
|
+
async function handleClientCodeChange(change, context) {
|
|
49467
|
+
const { repoPath, editorYaml, stagedOnly = false } = context;
|
|
49468
|
+
const { relativePath, changeType } = change;
|
|
49469
|
+
const renameResult = await handlePathRenaming(relativePath, "client_code", context);
|
|
49392
49470
|
if (renameResult.ignoreResult) return renameResult.ignoreResult;
|
|
49393
49471
|
const actualPath = renameResult.newRelativePath;
|
|
49394
49472
|
const isPackageInit = actualPath.endsWith("__init__.py");
|
|
49395
49473
|
const kind = isPackageInit ? "package" : "module";
|
|
49396
49474
|
const className = renameResult.pythonifiedName;
|
|
49397
49475
|
const templateInfo = findFormTemplateForCodePath(repoPath, actualPath, kind);
|
|
49398
|
-
if (templateInfo) return await handleClientCodeFormChange(
|
|
49476
|
+
if (templateInfo) return await handleClientCodeFormChange({
|
|
49477
|
+
templatePath: templateInfo.relativePath,
|
|
49478
|
+
templateInfo: {
|
|
49479
|
+
format: templateInfo.format,
|
|
49480
|
+
kind
|
|
49481
|
+
},
|
|
49482
|
+
changeType
|
|
49483
|
+
}, context);
|
|
49399
49484
|
const content = await readFileContent(repoPath, actualPath, stagedOnly);
|
|
49400
49485
|
return handleIdBasedOperation({
|
|
49401
49486
|
entityType: "modules",
|
|
@@ -49430,8 +49515,10 @@ var __webpack_exports__ = {};
|
|
|
49430
49515
|
}
|
|
49431
49516
|
return formData;
|
|
49432
49517
|
}
|
|
49433
|
-
async function buildFormTemplateData(
|
|
49434
|
-
const
|
|
49518
|
+
async function buildFormTemplateData(relativePath, templateInfo, context) {
|
|
49519
|
+
const { repoPath, stagedOnly = false } = context;
|
|
49520
|
+
const { kind } = templateInfo;
|
|
49521
|
+
const loadResult = await loadFormTemplateData(relativePath, templateInfo, context);
|
|
49435
49522
|
if (false === loadResult.ok) return {
|
|
49436
49523
|
formData: {},
|
|
49437
49524
|
className: "",
|
|
@@ -49465,7 +49552,9 @@ var __webpack_exports__ = {};
|
|
|
49465
49552
|
ignoreResult: null
|
|
49466
49553
|
};
|
|
49467
49554
|
}
|
|
49468
|
-
async function handleFormTemplateChange(
|
|
49555
|
+
async function handleFormTemplateChange(change, context) {
|
|
49556
|
+
const { editorYaml } = context;
|
|
49557
|
+
const { relativePath, changeType } = change;
|
|
49469
49558
|
const templateInfo = detectFormTemplate(relativePath);
|
|
49470
49559
|
if (!templateInfo) return {
|
|
49471
49560
|
type: "ignore",
|
|
@@ -49473,7 +49562,10 @@ var __webpack_exports__ = {};
|
|
|
49473
49562
|
};
|
|
49474
49563
|
const kind = templateInfo.kind;
|
|
49475
49564
|
const format = templateInfo.format;
|
|
49476
|
-
const result = await buildFormTemplateData(
|
|
49565
|
+
const result = await buildFormTemplateData(relativePath, {
|
|
49566
|
+
kind,
|
|
49567
|
+
format
|
|
49568
|
+
}, context);
|
|
49477
49569
|
if (result.ignoreResult) return result.ignoreResult;
|
|
49478
49570
|
const { formData, className } = result;
|
|
49479
49571
|
return handleIdBasedOperation({
|
|
@@ -49489,7 +49581,9 @@ var __webpack_exports__ = {};
|
|
|
49489
49581
|
subPathForCodeUpdate: null
|
|
49490
49582
|
});
|
|
49491
49583
|
}
|
|
49492
|
-
async function handleAssetChange(
|
|
49584
|
+
async function handleAssetChange(change, context) {
|
|
49585
|
+
const { repoPath, editorYaml, stagedOnly = false } = context;
|
|
49586
|
+
const { relativePath, changeType } = change;
|
|
49493
49587
|
const assetPath = relativePath.replace(/^theme[\/\\]assets[\/\\]/, "");
|
|
49494
49588
|
const fileBuffer = await readBinaryFileContent(repoPath, relativePath, stagedOnly);
|
|
49495
49589
|
const base64Content = fileBuffer.toString("base64");
|
|
@@ -49916,7 +50010,15 @@ var __webpack_exports__ = {};
|
|
|
49916
50010
|
originalFilePaths.push(change.path);
|
|
49917
50011
|
continue;
|
|
49918
50012
|
}
|
|
49919
|
-
const routeResult = await routeFileChange(
|
|
50013
|
+
const routeResult = await routeFileChange({
|
|
50014
|
+
relativePath: change.path,
|
|
50015
|
+
changeType: change.type,
|
|
50016
|
+
fromPath: change.from
|
|
50017
|
+
}, {
|
|
50018
|
+
repoPath: this.config.repoPath,
|
|
50019
|
+
editorYaml: this.config.editorYaml,
|
|
50020
|
+
stagedOnly: this.config.stagedOnly
|
|
50021
|
+
});
|
|
49920
50022
|
const results = Array.isArray(routeResult) ? routeResult : [
|
|
49921
50023
|
routeResult
|
|
49922
50024
|
];
|
|
@@ -50103,7 +50205,15 @@ var __webpack_exports__ = {};
|
|
|
50103
50205
|
const newSaveArray = [];
|
|
50104
50206
|
const newFilePaths = [];
|
|
50105
50207
|
for (const change of changes){
|
|
50106
|
-
const routeResult = await routeFileChange(
|
|
50208
|
+
const routeResult = await routeFileChange({
|
|
50209
|
+
relativePath: change.path,
|
|
50210
|
+
changeType: change.type,
|
|
50211
|
+
fromPath: change.from
|
|
50212
|
+
}, {
|
|
50213
|
+
repoPath: this.config.repoPath,
|
|
50214
|
+
editorYaml: this.config.editorYaml,
|
|
50215
|
+
stagedOnly: this.config.stagedOnly
|
|
50216
|
+
});
|
|
50107
50217
|
const results = Array.isArray(routeResult) ? routeResult : [
|
|
50108
50218
|
routeResult
|
|
50109
50219
|
];
|
|
@@ -50637,22 +50747,28 @@ var __webpack_exports__ = {};
|
|
|
50637
50747
|
appName
|
|
50638
50748
|
};
|
|
50639
50749
|
}
|
|
50640
|
-
async function validateBranchSyncStatus(git, branchName,
|
|
50750
|
+
async function validateBranchSyncStatus(git, branchName, options) {
|
|
50751
|
+
const { appId, anvilUrl, username } = options;
|
|
50641
50752
|
logger_logger.verbose(chalk_source.blue("Checking branch sync status..."));
|
|
50642
50753
|
let authToken;
|
|
50643
50754
|
try {
|
|
50644
50755
|
authToken = await auth_getValidAuthToken(anvilUrl, username);
|
|
50645
50756
|
} catch (e) {
|
|
50646
|
-
return validateViaAnvilServer(git, branchName,
|
|
50757
|
+
return validateViaAnvilServer(git, branchName, options);
|
|
50647
50758
|
}
|
|
50648
50759
|
try {
|
|
50649
|
-
return await validateViaGitFetch(git, branchName,
|
|
50760
|
+
return await validateViaGitFetch(git, branchName, {
|
|
50761
|
+
appId,
|
|
50762
|
+
anvilUrl,
|
|
50763
|
+
authToken
|
|
50764
|
+
});
|
|
50650
50765
|
} catch (e) {
|
|
50651
50766
|
logger_logger.verbose(chalk_source.yellow("Git fetch failed, trying server validation..."));
|
|
50652
|
-
return validateViaAnvilServer(git, branchName,
|
|
50767
|
+
return validateViaAnvilServer(git, branchName, options);
|
|
50653
50768
|
}
|
|
50654
50769
|
}
|
|
50655
|
-
async function validateViaGitFetch(git, branchName,
|
|
50770
|
+
async function validateViaGitFetch(git, branchName, options) {
|
|
50771
|
+
const { appId, anvilUrl, authToken } = options;
|
|
50656
50772
|
const baseUrl = new URL(anvilUrl);
|
|
50657
50773
|
const encodedToken = encodeURIComponent(authToken);
|
|
50658
50774
|
const gitPath = `/git/${appId}.git`;
|
|
@@ -50713,7 +50829,8 @@ var __webpack_exports__ = {};
|
|
|
50713
50829
|
throw errors_createGitError.fetchFailed(e.message);
|
|
50714
50830
|
}
|
|
50715
50831
|
}
|
|
50716
|
-
async function validateViaAnvilServer(git, branchName,
|
|
50832
|
+
async function validateViaAnvilServer(git, branchName, options) {
|
|
50833
|
+
const { appId, anvilUrl, username } = options;
|
|
50717
50834
|
logger_logger.verbose(chalk_source.blue("Validating sync status with Anvil server..."));
|
|
50718
50835
|
const authToken = await auth_getValidAuthToken(anvilUrl, username);
|
|
50719
50836
|
let commitId;
|
|
@@ -51378,7 +51495,7 @@ var __webpack_exports__ = {};
|
|
|
51378
51495
|
</body>
|
|
51379
51496
|
</html>`;
|
|
51380
51497
|
}
|
|
51381
|
-
const CLIENT_ID =
|
|
51498
|
+
const CLIENT_ID = ANVIL_SYNC_CLIENT_ID;
|
|
51382
51499
|
const SCOPES = "apps:read apps:write user:read";
|
|
51383
51500
|
function oauth_login_base64url(buf) {
|
|
51384
51501
|
return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
@@ -51441,7 +51558,8 @@ var __webpack_exports__ = {};
|
|
|
51441
51558
|
return text;
|
|
51442
51559
|
}
|
|
51443
51560
|
}
|
|
51444
|
-
async function exchangeAuthorizationCodeForTokens(anvilUrl,
|
|
51561
|
+
async function exchangeAuthorizationCodeForTokens(anvilUrl, options) {
|
|
51562
|
+
const { redirectUri, code, codeVerifier } = options;
|
|
51445
51563
|
const tokenResponse = await fetch(`${anvilUrl}/oauth/token`, {
|
|
51446
51564
|
method: "POST",
|
|
51447
51565
|
headers: {
|
|
@@ -51569,7 +51687,11 @@ var __webpack_exports__ = {};
|
|
|
51569
51687
|
const { code, error, recvState } = await codePromise;
|
|
51570
51688
|
if (recvState !== state) throw new Error("Invalid state received from OAuth callback");
|
|
51571
51689
|
if (error) throw new Error(`Error received from OAuth callback: ${error}`);
|
|
51572
|
-
const tokenData = await exchangeAuthorizationCodeForTokens(anvilUrl,
|
|
51690
|
+
const tokenData = await exchangeAuthorizationCodeForTokens(anvilUrl, {
|
|
51691
|
+
redirectUri,
|
|
51692
|
+
code: code,
|
|
51693
|
+
codeVerifier
|
|
51694
|
+
});
|
|
51573
51695
|
return login(anvilUrl, {
|
|
51574
51696
|
access_token: tokenData.access_token,
|
|
51575
51697
|
refresh_token: tokenData.refresh_token,
|
|
@@ -52309,7 +52431,6 @@ var __webpack_exports__ = {};
|
|
|
52309
52431
|
getValidAuthToken: auth_getValidAuthToken,
|
|
52310
52432
|
validateAppId: validateAppId,
|
|
52311
52433
|
listAppsForCheckout: listAppsForCheckout,
|
|
52312
|
-
runInteractiveLoginFlow: runInteractiveLoginFlow,
|
|
52313
52434
|
clone: async (repoUrl, destinationPath, options)=>{
|
|
52314
52435
|
const cloneArgs = [];
|
|
52315
52436
|
if (options?.branch) cloneArgs.push("--branch", options.branch);
|
|
@@ -52322,9 +52443,6 @@ var __webpack_exports__ = {};
|
|
|
52322
52443
|
},
|
|
52323
52444
|
hardenCheckoutGitAuth: hardenCheckoutGitAuth
|
|
52324
52445
|
};
|
|
52325
|
-
function isInteractiveSession() {
|
|
52326
|
-
return !!(process.stdin.isTTY && process.stdout.isTTY);
|
|
52327
|
-
}
|
|
52328
52446
|
function parseCheckoutInput(input) {
|
|
52329
52447
|
const trimmed = input.trim();
|
|
52330
52448
|
if (!trimmed) throw new Error("Input is required.");
|
|
@@ -52388,7 +52506,17 @@ var __webpack_exports__ = {};
|
|
|
52388
52506
|
name: "Cancel",
|
|
52389
52507
|
value: null
|
|
52390
52508
|
});
|
|
52391
|
-
return logger_logger.select("Multiple logged-in Anvil URLs found. Which one would you like to use?", choices, decision.urls[0]
|
|
52509
|
+
return logger_logger.select("Multiple logged-in Anvil URLs found. Which one would you like to use?", choices, decision.urls[0], {
|
|
52510
|
+
action: "`anvil checkout` URL selection",
|
|
52511
|
+
nonInteractiveHint: `Use --url <ANVIL_URL>. Available URLs: ${decision.urls.join(", ")}.`
|
|
52512
|
+
});
|
|
52513
|
+
}
|
|
52514
|
+
function resolveCheckoutUrlForApi(explicitUrl, parsedUrl) {
|
|
52515
|
+
if (explicitUrl) return normalizeAnvilUrl(explicitUrl);
|
|
52516
|
+
if (parsedUrl) return normalizeAnvilUrl(parsedUrl);
|
|
52517
|
+
const decision = decideFallbackUrl(void 0);
|
|
52518
|
+
if ("available-multiple" === decision.source) throw new Error(`Multiple logged-in Anvil URLs found: ${decision.urls.join(", ")}. Use --url <ANVIL_URL> to choose one.`);
|
|
52519
|
+
return decision.url;
|
|
52392
52520
|
}
|
|
52393
52521
|
async function isPathInsideGitRepo(targetPath) {
|
|
52394
52522
|
const resolved = external_path_default().resolve(targetPath);
|
|
@@ -52428,11 +52556,17 @@ var __webpack_exports__ = {};
|
|
|
52428
52556
|
logger_logger.verbose(chalk_source.cyan("Checking auth token for: ") + chalk_source.bold(username ? `${username} @ ${anvilUrl}` : anvilUrl));
|
|
52429
52557
|
return await deps.getValidAuthToken(anvilUrl, username);
|
|
52430
52558
|
} catch (e) {
|
|
52431
|
-
|
|
52432
|
-
|
|
52559
|
+
throw errors_createAuthError.required(`Not logged in to ${anvilUrl}. Run 'anvil login ${anvilUrl}' and retry.`);
|
|
52560
|
+
}
|
|
52561
|
+
}
|
|
52562
|
+
async function ensureCheckoutAuthTokenInteractive(anvilUrl, username, deps = defaultCheckoutDeps) {
|
|
52563
|
+
try {
|
|
52564
|
+
return await ensureCheckoutAuthToken(anvilUrl, username, deps);
|
|
52565
|
+
} catch (e) {
|
|
52566
|
+
assertCanPrompt("`anvil checkout` login prompt", `Run 'anvil login ${anvilUrl}' before checkout.`);
|
|
52433
52567
|
const shouldLogin = await logger_logger.confirm(`Not logged in to ${anvilUrl}. Log in now?`, true);
|
|
52434
|
-
if (!shouldLogin) throw
|
|
52435
|
-
await
|
|
52568
|
+
if (!shouldLogin) throw e;
|
|
52569
|
+
await runInteractiveLoginFlow(anvilUrl);
|
|
52436
52570
|
return deps.getValidAuthToken(anvilUrl, username);
|
|
52437
52571
|
}
|
|
52438
52572
|
}
|
|
@@ -52444,8 +52578,6 @@ var __webpack_exports__ = {};
|
|
|
52444
52578
|
logger_logger.verbose(chalk_source.cyan("Auto-selected account: ") + chalk_source.bold(accounts[0]));
|
|
52445
52579
|
return accounts[0];
|
|
52446
52580
|
}
|
|
52447
|
-
const interactive = process.stdin.isTTY && process.stdout.isTTY;
|
|
52448
|
-
if (!interactive) throw new Error(`Multiple accounts found for ${anvilUrl}. Use --user <USERNAME> to choose one.`);
|
|
52449
52581
|
const choices = accounts.map((acct)=>({
|
|
52450
52582
|
name: acct,
|
|
52451
52583
|
value: acct
|
|
@@ -52454,38 +52586,33 @@ var __webpack_exports__ = {};
|
|
|
52454
52586
|
name: "Cancel",
|
|
52455
52587
|
value: null
|
|
52456
52588
|
});
|
|
52457
|
-
return logger_logger.select(`Multiple accounts found for ${anvilUrl}. Which account should be used for checkout?`, choices, accounts[0]
|
|
52589
|
+
return logger_logger.select(`Multiple accounts found for ${anvilUrl}. Which account should be used for checkout?`, choices, accounts[0], {
|
|
52590
|
+
action: "`anvil checkout` account selection",
|
|
52591
|
+
nonInteractiveHint: `Use --user <USERNAME>. Available accounts: ${accounts.join(", ")}.`
|
|
52592
|
+
});
|
|
52593
|
+
}
|
|
52594
|
+
function resolveCheckoutUsernameForApi(anvilUrl, explicitUsername) {
|
|
52595
|
+
if (explicitUsername) return explicitUsername;
|
|
52596
|
+
const accounts = auth_getAccountsForUrl(anvilUrl);
|
|
52597
|
+
if (0 === accounts.length) return;
|
|
52598
|
+
if (1 === accounts.length) return accounts[0];
|
|
52599
|
+
throw new Error(`Multiple accounts found for ${anvilUrl}: ${accounts.join(", ")}. Use --user <USERNAME> to choose one.`);
|
|
52458
52600
|
}
|
|
52459
52601
|
async function executeCheckout(options, deps = defaultCheckoutDeps) {
|
|
52460
52602
|
let checkoutInput = options.input?.trim();
|
|
52461
|
-
|
|
52462
|
-
let preselectedUsername;
|
|
52463
|
-
if (!checkoutInput) {
|
|
52464
|
-
if (!isInteractiveSession()) throw new Error("`anvil checkout` without arguments requires an interactive TTY. Pass APP_ID or URL explicitly in non-interactive mode.");
|
|
52465
|
-
const selectedUrl = await resolveCheckoutUrl(options.url);
|
|
52466
|
-
if (!selectedUrl) return void logger_logger.info("Checkout cancelled.");
|
|
52467
|
-
preselectedAnvilUrl = selectedUrl;
|
|
52468
|
-
const selectedUsername = await resolveCheckoutUsername(selectedUrl, options.user);
|
|
52469
|
-
if (null === selectedUsername) return void logger_logger.info("Checkout cancelled.");
|
|
52470
|
-
preselectedUsername = selectedUsername || void 0;
|
|
52471
|
-
const selectedInput = await selectAppForCheckout(selectedUrl, preselectedUsername, deps, options.query);
|
|
52472
|
-
if (!selectedInput) return void logger_logger.info("Checkout cancelled.");
|
|
52473
|
-
checkoutInput = selectedInput;
|
|
52474
|
-
}
|
|
52603
|
+
if (!checkoutInput) throw new Error("Checkout input is required. Pass an app ID, editor URL, or /git URL explicitly.");
|
|
52475
52604
|
logger_logger.verbose(chalk_source.cyan("Checkout input: ") + chalk_source.bold(checkoutInput));
|
|
52476
52605
|
const parsed = parseCheckoutInput(checkoutInput);
|
|
52477
52606
|
logger_logger.verbose(chalk_source.cyan("Resolved app ID: ") + chalk_source.bold(parsed.appId));
|
|
52478
|
-
const anvilUrl =
|
|
52479
|
-
if (!anvilUrl)
|
|
52480
|
-
const resolvedUsername =
|
|
52481
|
-
if (null === resolvedUsername) return void logger_logger.info("Checkout cancelled.");
|
|
52607
|
+
const anvilUrl = resolveCheckoutUrlForApi(options.url, parsed.detectedUrl);
|
|
52608
|
+
if (!anvilUrl) throw new Error("Anvil URL is required. Use --url <ANVIL_URL> or pass an input URL containing the host.");
|
|
52609
|
+
const resolvedUsername = resolveCheckoutUsernameForApi(anvilUrl, options.user);
|
|
52482
52610
|
if (resolvedUsername) logger_logger.verbose(chalk_source.cyan("Using account: ") + chalk_source.bold(resolvedUsername));
|
|
52483
52611
|
else logger_logger.verbose(chalk_source.cyan("No account preselected; resolving after auth token lookup."));
|
|
52484
52612
|
const authToken = await ensureCheckoutAuthToken(anvilUrl, resolvedUsername, deps);
|
|
52485
52613
|
let checkoutUsername = resolvedUsername;
|
|
52486
52614
|
if (!checkoutUsername) {
|
|
52487
|
-
const inferredUsername =
|
|
52488
|
-
if (null === inferredUsername) return void logger_logger.info("Checkout cancelled.");
|
|
52615
|
+
const inferredUsername = resolveCheckoutUsernameForApi(anvilUrl, void 0);
|
|
52489
52616
|
if (!inferredUsername) throw new Error(`Could not determine account for ${anvilUrl}. Use --user <USERNAME> so checkout can bind repository credentials.`);
|
|
52490
52617
|
checkoutUsername = inferredUsername;
|
|
52491
52618
|
}
|
|
@@ -52505,8 +52632,6 @@ var __webpack_exports__ = {};
|
|
|
52505
52632
|
if (options.branch) logger_logger.verbose(chalk_source.cyan("Requested branch: ") + chalk_source.bold(options.branch));
|
|
52506
52633
|
if ("number" == typeof options.depth) logger_logger.verbose(chalk_source.cyan("Clone depth: ") + chalk_source.bold(String(options.depth)));
|
|
52507
52634
|
if (options.singleBranch) logger_logger.verbose(chalk_source.cyan("Single-branch clone enabled"));
|
|
52508
|
-
logger_logger.progress("checkout", `Checking out app ${parsed.appId} from ${anvilUrl}`);
|
|
52509
|
-
logger_logger.info(chalk_source.gray(` Destination directory: ${destinationDisplay}`));
|
|
52510
52635
|
await deps.clone(cloneUrl, destinationPath, {
|
|
52511
52636
|
branch: options.branch,
|
|
52512
52637
|
depth: options.depth,
|
|
@@ -52528,14 +52653,57 @@ var __webpack_exports__ = {};
|
|
|
52528
52653
|
} catch (e) {
|
|
52529
52654
|
throw new Error(`Checkout clone succeeded, but failed to configure repository credentials: ${errors_getErrorMessage(e)}. The repository exists at ${destinationDisplay}, but Git auth bridge setup is incomplete.`);
|
|
52530
52655
|
}
|
|
52531
|
-
|
|
52656
|
+
return {
|
|
52657
|
+
appId: parsed.appId,
|
|
52658
|
+
appName: validation.app_name,
|
|
52659
|
+
anvilUrl,
|
|
52660
|
+
destinationPath,
|
|
52661
|
+
destinationDisplay,
|
|
52662
|
+
username: checkoutUsername,
|
|
52663
|
+
remoteName
|
|
52664
|
+
};
|
|
52665
|
+
}
|
|
52666
|
+
async function executeCheckoutInteractive(options, deps = defaultCheckoutDeps) {
|
|
52667
|
+
let checkoutInput = options.input?.trim();
|
|
52668
|
+
let preselectedAnvilUrl;
|
|
52669
|
+
let preselectedUsername;
|
|
52670
|
+
if (!checkoutInput) {
|
|
52671
|
+
assertCanPrompt("`anvil checkout` without arguments", "Pass an app ID, editor URL, or /git URL. Use --url <ANVIL_URL> and --user <USERNAME> if needed.");
|
|
52672
|
+
const selectedUrl = await resolveCheckoutUrl(options.url);
|
|
52673
|
+
if (!selectedUrl) return void logger_logger.info("Checkout cancelled.");
|
|
52674
|
+
preselectedAnvilUrl = selectedUrl;
|
|
52675
|
+
const selectedUsername = await resolveCheckoutUsername(selectedUrl, options.user);
|
|
52676
|
+
if (null === selectedUsername) return void logger_logger.info("Checkout cancelled.");
|
|
52677
|
+
preselectedUsername = selectedUsername || void 0;
|
|
52678
|
+
const selectedInput = await selectAppForCheckout(selectedUrl, preselectedUsername, deps, options.query);
|
|
52679
|
+
if (!selectedInput) return void logger_logger.info("Checkout cancelled.");
|
|
52680
|
+
checkoutInput = selectedInput;
|
|
52681
|
+
}
|
|
52682
|
+
logger_logger.verbose(chalk_source.cyan("Checkout input: ") + chalk_source.bold(checkoutInput));
|
|
52683
|
+
const parsed = parseCheckoutInput(checkoutInput);
|
|
52684
|
+
logger_logger.verbose(chalk_source.cyan("Resolved app ID: ") + chalk_source.bold(parsed.appId));
|
|
52685
|
+
const anvilUrl = preselectedAnvilUrl || await resolveCheckoutUrl(options.url, parsed.detectedUrl);
|
|
52686
|
+
if (!anvilUrl) return void logger_logger.info("Checkout cancelled.");
|
|
52687
|
+
const resolvedUsername = preselectedUsername || await resolveCheckoutUsername(anvilUrl, options.user);
|
|
52688
|
+
if (null === resolvedUsername) return void logger_logger.info("Checkout cancelled.");
|
|
52689
|
+
if (resolvedUsername) logger_logger.verbose(chalk_source.cyan("Using account: ") + chalk_source.bold(resolvedUsername));
|
|
52690
|
+
else logger_logger.verbose(chalk_source.cyan("No account preselected; resolving after auth token lookup."));
|
|
52691
|
+
await ensureCheckoutAuthTokenInteractive(anvilUrl, resolvedUsername, deps);
|
|
52692
|
+
logger_logger.progress("checkout", `Checking out app ${parsed.appId} from ${anvilUrl}`);
|
|
52693
|
+
const result = await executeCheckout({
|
|
52694
|
+
...options,
|
|
52695
|
+
input: checkoutInput,
|
|
52696
|
+
url: anvilUrl,
|
|
52697
|
+
user: resolvedUsername || options.user
|
|
52698
|
+
}, deps);
|
|
52699
|
+
logger_logger.progressEnd("checkout", `Checked out ${result.appId} into ${result.destinationDisplay}`);
|
|
52532
52700
|
const preferredEditor = String(getConfig("preferredEditor") || "").trim();
|
|
52533
52701
|
const preferredEditorCommand = preferredEditor ? getPreferredEditorCommand(preferredEditor) : "";
|
|
52534
52702
|
if (options.open) {
|
|
52535
|
-
await checkout_openPathInEditorOrDefault(destinationPath, preferredEditorCommand);
|
|
52536
|
-
logger_logger.info(chalk_source.gray(`Opened ${destinationDisplay}`));
|
|
52703
|
+
await checkout_openPathInEditorOrDefault(result.destinationPath, preferredEditorCommand);
|
|
52704
|
+
logger_logger.info(chalk_source.gray(`Opened ${result.destinationDisplay}`));
|
|
52537
52705
|
}
|
|
52538
|
-
if (preferredEditorCommand && !options.open) if (isCommandAvailable(preferredEditorCommand)) logger_logger.info(chalk_source.cyan(`Next: ${preferredEditorCommand} ${destinationDisplay}`));
|
|
52706
|
+
if (preferredEditorCommand && !options.open) if (isCommandAvailable(preferredEditorCommand)) logger_logger.info(chalk_source.cyan(`Next: ${preferredEditorCommand} ${result.destinationDisplay}`));
|
|
52539
52707
|
else logger_logger.warn(`Preferred editor command '${preferredEditorCommand}' was not found in PATH. Run 'anvil configure' to choose an installed editor.`);
|
|
52540
52708
|
}
|
|
52541
52709
|
async function checkout_openPathInEditorOrDefault(destinationPath, preferredEditorCommand, deps) {
|
|
@@ -52546,7 +52714,7 @@ var __webpack_exports__ = {};
|
|
|
52546
52714
|
try {
|
|
52547
52715
|
const globalOptions = command?.optsWithGlobals() || options || {};
|
|
52548
52716
|
if ("number" == typeof options?.depth && (!Number.isFinite(options.depth) || options.depth <= 0)) throw new Error("--depth must be a positive integer");
|
|
52549
|
-
await
|
|
52717
|
+
await executeCheckoutInteractive({
|
|
52550
52718
|
input,
|
|
52551
52719
|
directory,
|
|
52552
52720
|
open: options?.open,
|
|
@@ -52569,7 +52737,8 @@ var __webpack_exports__ = {};
|
|
|
52569
52737
|
checkoutCommand.addHelpText("after", "\n" + chalk_source.bold("Examples:") + '\n anvil checkout http://localhost:3000/build/apps/APPID/code/assets/theme.css\n anvil checkout https://anvil.works/git/APPID.git\n anvil checkout APPID --url anvil.works\n anvil checkout APPID --branch master --depth 1 --single-branch\n anvil checkout APPID -O # open editor/file browser after checkout\n anvil checkout APPID my-local-folder --force\n anvil checkout # interactive search/select app list\n anvil checkout -Q "dashboard" # preseed picker search\n');
|
|
52570
52738
|
}
|
|
52571
52739
|
const DEFAULT_ANVIL_URL = resolveAnvilUrl();
|
|
52572
|
-
async function syncToLatest(repoPath, appId,
|
|
52740
|
+
async function syncToLatest(repoPath, appId, options) {
|
|
52741
|
+
const { anvilUrl, authToken, currentBranch, username } = options;
|
|
52573
52742
|
try {
|
|
52574
52743
|
const git = esm_default(repoPath);
|
|
52575
52744
|
const commitId = (await git.revparse([
|
|
@@ -52593,7 +52762,8 @@ var __webpack_exports__ = {};
|
|
|
52593
52762
|
throw errors_createGitError.commandFailed("sync", e instanceof Error ? e.message : String(e));
|
|
52594
52763
|
}
|
|
52595
52764
|
}
|
|
52596
|
-
async function api_watch(repoPath, appId,
|
|
52765
|
+
async function api_watch(repoPath, appId, options = {}) {
|
|
52766
|
+
const { anvilUrl = DEFAULT_ANVIL_URL, stagedOnly = false, username } = options;
|
|
52597
52767
|
repoPath = external_path_default().resolve(repoPath);
|
|
52598
52768
|
const authToken = await auth_getValidAuthToken(anvilUrl, username);
|
|
52599
52769
|
await verifyAuth(authToken, anvilUrl);
|
|
@@ -52620,7 +52790,11 @@ var __webpack_exports__ = {};
|
|
|
52620
52790
|
}
|
|
52621
52791
|
logger_logger.verbose(chalk_source.cyan("Current branch: ") + chalk_source.bold(currentBranch));
|
|
52622
52792
|
logger_logger.verbose(chalk_source.cyan("Current commit ID: ") + chalk_source.gray(commitId));
|
|
52623
|
-
const syncStatus = await validateBranchSyncStatus(git, currentBranch,
|
|
52793
|
+
const syncStatus = await validateBranchSyncStatus(git, currentBranch, {
|
|
52794
|
+
appId,
|
|
52795
|
+
anvilUrl,
|
|
52796
|
+
username
|
|
52797
|
+
});
|
|
52624
52798
|
let hasUncommittedChanges = false;
|
|
52625
52799
|
try {
|
|
52626
52800
|
const status = await git.status();
|
|
@@ -52969,7 +53143,11 @@ var __webpack_exports__ = {};
|
|
|
52969
53143
|
async function recheckSyncStatus(previousCategory, previousBranch, options) {
|
|
52970
53144
|
try {
|
|
52971
53145
|
logger_logger.progress("verify", "Verifying repository status...");
|
|
52972
|
-
const freshSession = await api_watch(options.repoPath, options.appId,
|
|
53146
|
+
const freshSession = await api_watch(options.repoPath, options.appId, {
|
|
53147
|
+
anvilUrl: options.anvilUrl,
|
|
53148
|
+
stagedOnly: options.stagedOnly,
|
|
53149
|
+
username: options.username
|
|
53150
|
+
});
|
|
52973
53151
|
logger_logger.progressEnd("verify");
|
|
52974
53152
|
const currentCategory = getSyncStateCategory(freshSession.syncStatus);
|
|
52975
53153
|
const currentBranch = freshSession.getBranchName() || "master";
|
|
@@ -52988,7 +53166,11 @@ var __webpack_exports__ = {};
|
|
|
52988
53166
|
async function recreateSessionAndValidate(options) {
|
|
52989
53167
|
logger_logger.progress("init", "Restarting watch session...");
|
|
52990
53168
|
try {
|
|
52991
|
-
const newSession = await api_watch(options.repoPath, options.appId,
|
|
53169
|
+
const newSession = await api_watch(options.repoPath, options.appId, {
|
|
53170
|
+
anvilUrl: options.anvilUrl,
|
|
53171
|
+
stagedOnly: options.stagedOnly,
|
|
53172
|
+
username: options.username
|
|
53173
|
+
});
|
|
52992
53174
|
logger_logger.progressEnd("init");
|
|
52993
53175
|
return await checkSyncStatusAndStart(newSession, options);
|
|
52994
53176
|
} catch (e) {
|
|
@@ -53201,7 +53383,12 @@ var __webpack_exports__ = {};
|
|
|
53201
53383
|
}
|
|
53202
53384
|
logger_logger.progress("sync-latest", "Syncing to latest version from Anvil...");
|
|
53203
53385
|
try {
|
|
53204
|
-
const newCommitId = await syncToLatest(options.repoPath, options.appId,
|
|
53386
|
+
const newCommitId = await syncToLatest(options.repoPath, options.appId, {
|
|
53387
|
+
anvilUrl: options.anvilUrl,
|
|
53388
|
+
authToken,
|
|
53389
|
+
currentBranch: branchName,
|
|
53390
|
+
username: options.username
|
|
53391
|
+
});
|
|
53205
53392
|
logger_logger.progressEnd("sync-latest", `Synced to latest version: ${newCommitId.substring(0, 8)}`);
|
|
53206
53393
|
} catch (e) {
|
|
53207
53394
|
logger_logger.progressEnd("sync-latest", "Failed");
|
|
@@ -53228,7 +53415,11 @@ var __webpack_exports__ = {};
|
|
|
53228
53415
|
if (actualBranch !== newBranch) logger_logger.verbose(chalk_source.yellow(`Branch changed again to ${chalk_source.bold(actualBranch)}, using that instead`));
|
|
53229
53416
|
logger_logger.progress("init", "Initializing watch session...");
|
|
53230
53417
|
try {
|
|
53231
|
-
const newSession = await api_watch(repoPath, appId,
|
|
53418
|
+
const newSession = await api_watch(repoPath, appId, {
|
|
53419
|
+
anvilUrl,
|
|
53420
|
+
stagedOnly,
|
|
53421
|
+
username: options.username
|
|
53422
|
+
});
|
|
53232
53423
|
logger_logger.progressEnd("init");
|
|
53233
53424
|
const started = await checkSyncStatusAndStart(newSession, options);
|
|
53234
53425
|
if (!started) process.exit(0);
|
|
@@ -53441,7 +53632,11 @@ var __webpack_exports__ = {};
|
|
|
53441
53632
|
if (stagedOnly) logger_logger.info(chalk_source.yellow("▸ Staged-only mode: Only staged changes will be synced"));
|
|
53442
53633
|
if (autoMode) logger_logger.info(chalk_source.cyan("▸ Auto mode: Will automatically restart on branch changes and sync when behind"));
|
|
53443
53634
|
logger_logger.progress("init", "Initializing watch session...");
|
|
53444
|
-
const session = await api_watch(repoPath, finalAppId,
|
|
53635
|
+
const session = await api_watch(repoPath, finalAppId, {
|
|
53636
|
+
anvilUrl,
|
|
53637
|
+
stagedOnly,
|
|
53638
|
+
username
|
|
53639
|
+
});
|
|
53445
53640
|
logger_logger.progressEnd("init");
|
|
53446
53641
|
if (openAfterValidation) await openWatchPath(resolveWatchOpenPath(repoPath));
|
|
53447
53642
|
logger_logger.verbose(chalk_source.blue("Watching for file changes..."));
|
|
@@ -53897,11 +54092,8 @@ var __webpack_exports__ = {};
|
|
|
53897
54092
|
if (1 === accounts.length) return accounts[0];
|
|
53898
54093
|
return `${accounts.length} accounts`;
|
|
53899
54094
|
}
|
|
53900
|
-
function configure_isInteractiveSession() {
|
|
53901
|
-
return !!(process.stdin.isTTY && process.stdout.isTTY);
|
|
53902
|
-
}
|
|
53903
54095
|
async function runConfigureFlow(version, deps = configure_defaultDeps) {
|
|
53904
|
-
|
|
54096
|
+
assertCanPrompt("`anvil configure`", "Use `anvil config set anvilUrl <URL>`, `anvil config set preferredEditor <COMMAND>`, `anvil config set verbose <true|false>`, and `anvil login <URL>` instead.");
|
|
53905
54097
|
console.log();
|
|
53906
54098
|
logger_logger.info(chalk_source.cyan.bold("Anvil Configuration"));
|
|
53907
54099
|
console.log();
|