@anvil-works/anvil-cli 0.8.0-canary.9 → 0.8.0-dev.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/README.md +54 -0
- package/dist/WatchSession.d.ts +2 -0
- package/dist/WatchSession.d.ts.map +1 -1
- package/dist/api.d.ts +8 -2
- package/dist/api.d.ts.map +1 -1
- package/dist/cli.js +2799 -1249
- package/dist/commands/appDetection.d.ts +68 -1
- package/dist/commands/appDetection.d.ts.map +1 -1
- package/dist/commands/checkout.d.ts +1 -0
- package/dist/commands/checkout.d.ts.map +1 -1
- package/dist/commands/configure.d.ts.map +1 -1
- package/dist/commands/create.d.ts +52 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/db.d.ts +3 -0
- package/dist/commands/db.d.ts.map +1 -0
- package/dist/commands/deps.d.ts.map +1 -1
- package/dist/commands/env.d.ts +10 -0
- package/dist/commands/env.d.ts.map +1 -0
- package/dist/commands/index.d.ts +6 -1
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/modelToken.d.ts +33 -0
- package/dist/commands/modelToken.d.ts.map +1 -0
- package/dist/commands/repl.d.ts +3 -0
- package/dist/commands/repl.d.ts.map +1 -0
- package/dist/commands/secret.d.ts +3 -0
- package/dist/commands/secret.d.ts.map +1 -0
- package/dist/commands/test.d.ts +26 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/watch.d.ts +1 -25
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/config.d.ts +3 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/errors.d.ts +11 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/formTemplateValidation.d.ts.map +1 -1
- package/dist/index.js +1466 -994
- package/dist/program.d.ts.map +1 -1
- package/dist/services/anvil-api.d.ts +20 -0
- package/dist/services/anvil-api.d.ts.map +1 -1
- package/dist/services/auth.d.ts +42 -3
- package/dist/services/auth.d.ts.map +1 -1
- package/dist/services/db.d.ts +9 -0
- package/dist/services/db.d.ts.map +1 -0
- package/dist/services/deps.d.ts +5 -2
- package/dist/services/deps.d.ts.map +1 -1
- package/dist/services/environment.d.ts +20 -0
- package/dist/services/environment.d.ts.map +1 -0
- package/dist/services/git-auth.d.ts +35 -0
- package/dist/services/git-auth.d.ts.map +1 -1
- package/dist/services/git.d.ts +1 -0
- package/dist/services/git.d.ts.map +1 -1
- package/dist/services/http.d.ts +2 -0
- package/dist/services/http.d.ts.map +1 -0
- package/dist/services/path-open.d.ts +1 -0
- package/dist/services/path-open.d.ts.map +1 -1
- package/dist/services/repl.d.ts +20 -0
- package/dist/services/repl.d.ts.map +1 -0
- package/dist/services/secret.d.ts +43 -0
- package/dist/services/secret.d.ts.map +1 -0
- package/dist/services/server-tests.d.ts +47 -0
- package/dist/services/server-tests.d.ts.map +1 -0
- package/dist/validateFormTemplateHtml.d.ts.map +1 -1
- package/dist/validatePython.d.ts.map +1 -1
- package/dist/watch/SaveProcessor.d.ts +2 -0
- package/dist/watch/SaveProcessor.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/commands/tables.d.ts +0 -7
- package/dist/commands/tables.d.ts.map +0 -1
- package/dist/services/tables.d.ts +0 -27
- package/dist/services/tables.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -7373,18 +7373,19 @@ var __webpack_exports__ = {};
|
|
|
7373
7373
|
AppIdWithContext: ()=>anvil_api_namespaceObject.AppIdWithContext,
|
|
7374
7374
|
inspectCredentialHelperCommand: ()=>inspectCredentialHelperCommand,
|
|
7375
7375
|
executeCheckout: ()=>executeCheckout,
|
|
7376
|
+
executeCreate: ()=>executeCreate,
|
|
7376
7377
|
validateCheckoutDestination: ()=>validateCheckoutDestination,
|
|
7377
7378
|
DeviceAuthorizationResponse: ()=>oauth_login_namespaceObject.DeviceAuthorizationResponse,
|
|
7378
7379
|
OAuthTokenResponse: ()=>oauth_login_namespaceObject.OAuthTokenResponse,
|
|
7380
|
+
REFRESH_REQUEST_TIMEOUT_MS: ()=>REFRESH_REQUEST_TIMEOUT_MS,
|
|
7379
7381
|
WatchSession: ()=>WatchSession_WatchSession,
|
|
7380
7382
|
parseConfigSetValue: ()=>parseConfigSetValue,
|
|
7381
|
-
requestDeviceAuthorization: ()=>requestDeviceAuthorization,
|
|
7382
7383
|
getGitPushUrl: ()=>anvil_api_getGitPushUrl,
|
|
7384
|
+
requestDeviceAuthorization: ()=>requestDeviceAuthorization,
|
|
7383
7385
|
requireEnvironmentBranch: ()=>requireEnvironmentBranch,
|
|
7384
7386
|
setAuthTokensForAccount: ()=>setAccountTokens,
|
|
7385
|
-
validateAnvilApp: ()=>validation_validateAnvilApp,
|
|
7386
7387
|
ValidateAppIdResponse: ()=>anvil_api_namespaceObject.ValidateAppIdResponse,
|
|
7387
|
-
|
|
7388
|
+
getModelToken: ()=>getModelToken,
|
|
7388
7389
|
formatValidationPath: ()=>formatValidationPath,
|
|
7389
7390
|
resolveAnvilUrl: ()=>resolveAnvilUrl,
|
|
7390
7391
|
createCheckoutPickerSource: ()=>createCheckoutPickerSource,
|
|
@@ -7392,12 +7393,13 @@ var __webpack_exports__ = {};
|
|
|
7392
7393
|
parseCheckoutInput: ()=>parseCheckoutInput,
|
|
7393
7394
|
formatGitAuthDoctorReport: ()=>formatGitAuthDoctorReport,
|
|
7394
7395
|
resetConfig: ()=>resetConfig,
|
|
7396
|
+
MODEL_TOKEN_HELPER_FILENAME: ()=>MODEL_TOKEN_HELPER_FILENAME,
|
|
7395
7397
|
FormTemplateValidationResult: ()=>validators_namespaceObject.FormTemplateValidationResult,
|
|
7396
7398
|
createWatchDiagnostic: ()=>createWatchDiagnostic,
|
|
7397
7399
|
ValidationTarget: ()=>validators_namespaceObject.ValidationTarget,
|
|
7398
7400
|
detectAppIdsByCommitLookup: ()=>anvil_api_detectAppIdsByCommitLookup,
|
|
7399
7401
|
sanitizeDirectoryName: ()=>sanitizeDirectoryName,
|
|
7400
|
-
|
|
7402
|
+
validateAnvilApp: ()=>validation_validateAnvilApp,
|
|
7401
7403
|
LoginResult: ()=>auth_namespaceObject.LoginResult,
|
|
7402
7404
|
listAppsForCheckout: ()=>listAppsForCheckout,
|
|
7403
7405
|
getInstalledPreferredEditors: ()=>getInstalledPreferredEditors,
|
|
@@ -7406,8 +7408,11 @@ var __webpack_exports__ = {};
|
|
|
7406
7408
|
CheckoutExecutionDeps: ()=>checkout_namespaceObject.CheckoutExecutionDeps,
|
|
7407
7409
|
validateFormTemplateHtml: ()=>validateFormTemplateHtml,
|
|
7408
7410
|
ValidateBranchSyncStatusOptions: ()=>validation_namespaceObject.ValidateBranchSyncStatusOptions,
|
|
7411
|
+
validatePath: ()=>validatePath,
|
|
7412
|
+
withRepoAuthFileLock: ()=>withRepoAuthFileLock,
|
|
7409
7413
|
BranchSyncStatus: ()=>validation_namespaceObject.BranchSyncStatus,
|
|
7410
7414
|
getLatestVersion: ()=>getLatestVersion,
|
|
7415
|
+
getModelTokenHelperScript: ()=>getModelTokenHelperScript,
|
|
7411
7416
|
isDirectoryNonEmpty: ()=>isDirectoryNonEmpty,
|
|
7412
7417
|
syncToLatest: ()=>src_api_syncToLatest,
|
|
7413
7418
|
filterCandidates: ()=>anvil_api_filterCandidates,
|
|
@@ -7416,7 +7421,7 @@ var __webpack_exports__ = {};
|
|
|
7416
7421
|
isPathInsideGitRepo: ()=>isPathInsideGitRepo,
|
|
7417
7422
|
normalizeAnvilUrl: ()=>config_normalizeAnvilUrl,
|
|
7418
7423
|
ValidationIssue: ()=>validators_namespaceObject.ValidationIssue,
|
|
7419
|
-
|
|
7424
|
+
verifyAndStoreTokens: ()=>auth_verifyAndStoreTokens,
|
|
7420
7425
|
readEnvironmentPid: ()=>environment_readEnvironmentPid,
|
|
7421
7426
|
validateFormTemplate: ()=>validateFormTemplate,
|
|
7422
7427
|
preferredEditors: ()=>preferredEditors,
|
|
@@ -7428,21 +7433,26 @@ var __webpack_exports__ = {};
|
|
|
7428
7433
|
validateBranchSyncStatus: ()=>validation_validateBranchSyncStatus,
|
|
7429
7434
|
checkUncommittedChanges: ()=>api_checkUncommittedChanges,
|
|
7430
7435
|
hasTokensForUrl: ()=>auth_hasTokensForUrl,
|
|
7436
|
+
writeEnvironmentPid: ()=>writeEnvironmentPid,
|
|
7431
7437
|
AnvilYamlValidationResult: ()=>validators_namespaceObject.AnvilYamlValidationResult,
|
|
7432
7438
|
ValidatePathResult: ()=>validators_namespaceObject.ValidatePathResult,
|
|
7433
7439
|
getSettableConfigKeys: ()=>getSettableConfigKeys,
|
|
7434
7440
|
logout: ()=>logout,
|
|
7435
7441
|
TokenData: ()=>auth_namespaceObject.TokenData,
|
|
7436
7442
|
detectAppIdsFromAllRemotes: ()=>anvil_api_detectAppIdsFromAllRemotes,
|
|
7443
|
+
executeModelTokenOperation: ()=>executeModelTokenOperation,
|
|
7437
7444
|
getWebSocketUrl: ()=>getWebSocketUrl,
|
|
7438
7445
|
getAllConfig: ()=>getAllConfig,
|
|
7439
7446
|
isCommandAvailable: ()=>config_isCommandAvailable,
|
|
7440
7447
|
setInMemoryTokens: ()=>setInMemoryTokens,
|
|
7441
7448
|
validateAppId: ()=>anvil_api_validateAppId,
|
|
7442
7449
|
pollDeviceAuthorization: ()=>pollDeviceAuthorization,
|
|
7450
|
+
createAnvilApp: ()=>createAnvilApp,
|
|
7443
7451
|
getValidAuthToken: ()=>auth_getValidAuthToken,
|
|
7452
|
+
CreatedAnvilApp: ()=>anvil_api_namespaceObject.CreatedAnvilApp,
|
|
7444
7453
|
watch: ()=>src_api_watch,
|
|
7445
7454
|
deleteConfig: ()=>deleteConfig,
|
|
7455
|
+
installModelTokenHelperScript: ()=>installModelTokenHelperScript,
|
|
7446
7456
|
getGitFetchUrl: ()=>anvil_api_getGitFetchUrl,
|
|
7447
7457
|
PreferredEditor: ()=>config_namespaceObject.PreferredEditor,
|
|
7448
7458
|
getAvailableAnvilUrls: ()=>getAvailableAnvilUrls,
|
|
@@ -7455,8 +7465,12 @@ var __webpack_exports__ = {};
|
|
|
7455
7465
|
CheckoutResult: ()=>checkout_namespaceObject.CheckoutResult,
|
|
7456
7466
|
ParsedCheckoutInput: ()=>checkout_namespaceObject.ParsedCheckoutInput,
|
|
7457
7467
|
parseCredentialHelperCommand: ()=>parseCredentialHelperCommand,
|
|
7458
|
-
|
|
7468
|
+
CreateCheckoutError: ()=>CreateCheckoutError,
|
|
7469
|
+
GetValidAuthTokenOptions: ()=>auth_namespaceObject.GetValidAuthTokenOptions,
|
|
7470
|
+
MODEL_TOKEN_LOCK_TIMEOUT_MS: ()=>MODEL_TOKEN_LOCK_TIMEOUT_MS,
|
|
7459
7471
|
getDefaultDestinationDirectory: ()=>getDefaultDestinationDirectory,
|
|
7472
|
+
AUTH_FILE_LOCK_DEFAULTS: ()=>AUTH_FILE_LOCK_DEFAULTS,
|
|
7473
|
+
clearInMemoryTokens: ()=>clearInMemoryTokens,
|
|
7460
7474
|
lookupByCommit: ()=>lookupByCommit,
|
|
7461
7475
|
AppIdCandidate: ()=>anvil_api_namespaceObject.AppIdCandidate,
|
|
7462
7476
|
verifyAuth: ()=>auth_verifyAuth
|
|
@@ -7473,6 +7487,7 @@ var __webpack_exports__ = {};
|
|
|
7473
7487
|
P$: ()=>config_isCommandAvailable,
|
|
7474
7488
|
n: ()=>config_isDevMode,
|
|
7475
7489
|
Wj: ()=>config_isTestMode,
|
|
7490
|
+
Wc: ()=>config_normalizeAnvilOrigin,
|
|
7476
7491
|
Vl: ()=>config_normalizeAnvilUrl,
|
|
7477
7492
|
PW: ()=>parseConfigSetValue,
|
|
7478
7493
|
cx: ()=>preferredEditors,
|
|
@@ -7485,12 +7500,14 @@ var __webpack_exports__ = {};
|
|
|
7485
7500
|
__webpack_require__.r(auth_namespaceObject);
|
|
7486
7501
|
__webpack_require__.d(auth_namespaceObject, {
|
|
7487
7502
|
fg: ()=>ANVIL_SYNC_CLIENT_ID,
|
|
7503
|
+
ru: ()=>REFRESH_REQUEST_TIMEOUT_MS,
|
|
7488
7504
|
Ou: ()=>clearInMemoryTokens,
|
|
7489
7505
|
Fr: ()=>auth_getAccountsForUrl,
|
|
7490
7506
|
u5: ()=>getAvailableAnvilUrls,
|
|
7491
7507
|
_p: ()=>auth_getValidAuthToken,
|
|
7492
7508
|
Fi: ()=>auth_hasTokensForUrl,
|
|
7493
7509
|
ri: ()=>logout,
|
|
7510
|
+
UE: ()=>auth_resolveAuthAnvilUrl,
|
|
7494
7511
|
f5: ()=>setInMemoryTokens,
|
|
7495
7512
|
iT: ()=>auth_setRepoContext,
|
|
7496
7513
|
CQ: ()=>auth_verifyAndStoreTokens,
|
|
@@ -7499,6 +7516,7 @@ var __webpack_exports__ = {};
|
|
|
7499
7516
|
var anvil_api_namespaceObject = {};
|
|
7500
7517
|
__webpack_require__.r(anvil_api_namespaceObject);
|
|
7501
7518
|
__webpack_require__.d(anvil_api_namespaceObject, {
|
|
7519
|
+
gr: ()=>createAnvilApp,
|
|
7502
7520
|
lx: ()=>anvil_api_detectAppIdsByCommitLookup,
|
|
7503
7521
|
NZ: ()=>anvil_api_detectAppIdsFromAllRemotes,
|
|
7504
7522
|
rZ: ()=>anvil_api_filterCandidates,
|
|
@@ -7541,6 +7559,7 @@ var __webpack_exports__ = {};
|
|
|
7541
7559
|
A9: ()=>isDirectoryNonEmpty,
|
|
7542
7560
|
oU: ()=>isPathInsideGitRepo,
|
|
7543
7561
|
Qx: ()=>parseCheckoutInput,
|
|
7562
|
+
B6: ()=>resolveCheckoutUrlForApi,
|
|
7544
7563
|
KV: ()=>sanitizeDirectoryName,
|
|
7545
7564
|
Bc: ()=>validateCheckoutDestination
|
|
7546
7565
|
});
|
|
@@ -13097,12 +13116,25 @@ var __webpack_exports__ = {};
|
|
|
13097
13116
|
if (!urlInput || "string" != typeof urlInput) return urlInput;
|
|
13098
13117
|
let url = urlInput.trim();
|
|
13099
13118
|
url = url.replace(/\/+$/, "");
|
|
13100
|
-
if ("localhost" === url
|
|
13101
|
-
if (
|
|
13102
|
-
if (
|
|
13103
|
-
if (/^https?:\/\//.test(url)) return url;
|
|
13119
|
+
if ("localhost" === url) return "http://localhost:3000";
|
|
13120
|
+
if (url.startsWith("localhost:")) return `http://${url}`;
|
|
13121
|
+
if (/^https?:\/\//i.test(url)) return url;
|
|
13104
13122
|
return `https://${url}`;
|
|
13105
13123
|
}
|
|
13124
|
+
function config_normalizeAnvilOrigin(input) {
|
|
13125
|
+
try {
|
|
13126
|
+
const raw = input.trim();
|
|
13127
|
+
const normalized = config_normalizeAnvilUrl(raw);
|
|
13128
|
+
const url = new URL(raw.includes("://") ? raw : normalized);
|
|
13129
|
+
if (![
|
|
13130
|
+
"http:",
|
|
13131
|
+
"https:"
|
|
13132
|
+
].includes(url.protocol) || url.username || url.password || "/" !== url.pathname || url.search || url.hash) throw new Error("Invalid origin");
|
|
13133
|
+
return normalized;
|
|
13134
|
+
} catch {
|
|
13135
|
+
throw new Error("Server URL must be an HTTP(S) origin without credentials, a path, query, or fragment.");
|
|
13136
|
+
}
|
|
13137
|
+
}
|
|
13106
13138
|
function resolveAnvilUrl() {
|
|
13107
13139
|
const fromConfig = config_getConfig("anvilUrl");
|
|
13108
13140
|
if ("string" == typeof fromConfig && fromConfig.trim()) return fromConfig.trim();
|
|
@@ -13365,9 +13397,10 @@ var __webpack_exports__ = {};
|
|
|
13365
13397
|
type: "auth_invalid",
|
|
13366
13398
|
message
|
|
13367
13399
|
}),
|
|
13368
|
-
refreshFailed: (message)=>({
|
|
13400
|
+
refreshFailed: (message, status)=>({
|
|
13369
13401
|
type: "token_refresh_failed",
|
|
13370
|
-
message
|
|
13402
|
+
message,
|
|
13403
|
+
status
|
|
13371
13404
|
})
|
|
13372
13405
|
};
|
|
13373
13406
|
const createAppError = {
|
|
@@ -13584,6 +13617,7 @@ var __webpack_exports__ = {};
|
|
|
13584
13617
|
const external_module_namespaceObject = require("module");
|
|
13585
13618
|
const requireFromHere = (0, external_module_namespaceObject.createRequire)(__filename);
|
|
13586
13619
|
const GIT_CREDENTIAL_HELPER_FILENAME = "anvil-credential-helper.cjs";
|
|
13620
|
+
const MODEL_TOKEN_HELPER_FILENAME = "anvil-model-token-helper.cjs";
|
|
13587
13621
|
const GIT_CREDENTIAL_HELPER_LOCATOR = `$(git rev-parse --git-common-dir)/${GIT_CREDENTIAL_HELPER_FILENAME}`;
|
|
13588
13622
|
function getUrlConfigKey(appId) {
|
|
13589
13623
|
return `anvil.auth.${appId}.url`;
|
|
@@ -13674,6 +13708,38 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13674
13708
|
});
|
|
13675
13709
|
`;
|
|
13676
13710
|
}
|
|
13711
|
+
function getModelTokenHelperScript(modulePath) {
|
|
13712
|
+
return `#!/usr/bin/env node
|
|
13713
|
+
"use strict";
|
|
13714
|
+
|
|
13715
|
+
const { execFileSync } = require("child_process");
|
|
13716
|
+
const { executeModelTokenOperation } = require(${JSON.stringify(modulePath)});
|
|
13717
|
+
|
|
13718
|
+
function resolveRepoPath() {
|
|
13719
|
+
return execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
13720
|
+
cwd: process.cwd(),
|
|
13721
|
+
encoding: "utf8",
|
|
13722
|
+
}).trim();
|
|
13723
|
+
}
|
|
13724
|
+
|
|
13725
|
+
Promise.resolve()
|
|
13726
|
+
.then(() => executeModelTokenOperation({ repoPath: resolveRepoPath() }))
|
|
13727
|
+
.catch((e) => {
|
|
13728
|
+
process.stderr.write("anvil model token helper failed: " + ((e && e.message) || e) + "\\n");
|
|
13729
|
+
process.exit(1);
|
|
13730
|
+
});
|
|
13731
|
+
`;
|
|
13732
|
+
}
|
|
13733
|
+
async function installModelTokenHelperScript(helperPath, options) {
|
|
13734
|
+
await external_fs_.promises.mkdir(external_path_default().dirname(helperPath), {
|
|
13735
|
+
recursive: true
|
|
13736
|
+
});
|
|
13737
|
+
await external_fs_.promises.writeFile(helperPath, getModelTokenHelperScript(options?.modulePath ?? getCredentialHelperModulePath()), {
|
|
13738
|
+
mode: 448
|
|
13739
|
+
});
|
|
13740
|
+
await external_fs_.promises.chmod(helperPath, 448);
|
|
13741
|
+
return helperPath;
|
|
13742
|
+
}
|
|
13677
13743
|
function findPackageRoot(startPath) {
|
|
13678
13744
|
let dir = external_fs_default().existsSync(startPath) && external_fs_default().statSync(startPath).isDirectory() ? startPath : external_path_default().dirname(startPath);
|
|
13679
13745
|
while(true){
|
|
@@ -13801,6 +13867,76 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13801
13867
|
function getAuthFilePath(gitDir) {
|
|
13802
13868
|
return external_path_default().join(gitDir, "anvil-auth.json");
|
|
13803
13869
|
}
|
|
13870
|
+
const AUTH_FILE_LOCK_DEFAULTS = {
|
|
13871
|
+
staleMs: 30000,
|
|
13872
|
+
timeoutMs: 60000,
|
|
13873
|
+
retryDelayMs: 100,
|
|
13874
|
+
heartbeatMs: 5000
|
|
13875
|
+
};
|
|
13876
|
+
function git_auth_delay(ms) {
|
|
13877
|
+
return new Promise((resolve)=>setTimeout(resolve, ms));
|
|
13878
|
+
}
|
|
13879
|
+
async function acquireAuthFileLock(lockPath, options) {
|
|
13880
|
+
const deadline = Date.now() + options.timeoutMs;
|
|
13881
|
+
while(true){
|
|
13882
|
+
try {
|
|
13883
|
+
const handle = await external_fs_.promises.open(lockPath, "wx", 384);
|
|
13884
|
+
try {
|
|
13885
|
+
await handle.writeFile(JSON.stringify({
|
|
13886
|
+
pid: process.pid,
|
|
13887
|
+
acquiredAt: new Date().toISOString()
|
|
13888
|
+
}));
|
|
13889
|
+
} finally{
|
|
13890
|
+
await handle.close();
|
|
13891
|
+
}
|
|
13892
|
+
return;
|
|
13893
|
+
} catch (e) {
|
|
13894
|
+
if ("EEXIST" !== e.code) throw e;
|
|
13895
|
+
}
|
|
13896
|
+
try {
|
|
13897
|
+
const lockStat = await external_fs_.promises.stat(lockPath);
|
|
13898
|
+
if (Date.now() - lockStat.mtimeMs > options.staleMs) {
|
|
13899
|
+
await external_fs_.promises.rm(lockPath, {
|
|
13900
|
+
force: true
|
|
13901
|
+
});
|
|
13902
|
+
continue;
|
|
13903
|
+
}
|
|
13904
|
+
} catch {
|
|
13905
|
+
continue;
|
|
13906
|
+
}
|
|
13907
|
+
if (Date.now() >= deadline) throw new Error(`Timed out waiting for the Anvil auth file lock at ${lockPath}`);
|
|
13908
|
+
await git_auth_delay(options.retryDelayMs);
|
|
13909
|
+
}
|
|
13910
|
+
}
|
|
13911
|
+
async function withRepoAuthFileLock(repoPath, fn, options) {
|
|
13912
|
+
const gitDir = await getRepositoryGitDir(repoPath);
|
|
13913
|
+
const lockPath = `${getAuthFilePath(gitDir)}.lock`;
|
|
13914
|
+
const lockOptions = {
|
|
13915
|
+
...AUTH_FILE_LOCK_DEFAULTS,
|
|
13916
|
+
...options
|
|
13917
|
+
};
|
|
13918
|
+
await external_fs_.promises.mkdir(external_path_default().dirname(lockPath), {
|
|
13919
|
+
recursive: true
|
|
13920
|
+
});
|
|
13921
|
+
await acquireAuthFileLock(lockPath, lockOptions);
|
|
13922
|
+
const heartbeat = startAuthFileLockHeartbeat(lockPath, lockOptions.heartbeatMs);
|
|
13923
|
+
try {
|
|
13924
|
+
return await fn();
|
|
13925
|
+
} finally{
|
|
13926
|
+
clearInterval(heartbeat);
|
|
13927
|
+
await external_fs_.promises.rm(lockPath, {
|
|
13928
|
+
force: true
|
|
13929
|
+
});
|
|
13930
|
+
}
|
|
13931
|
+
}
|
|
13932
|
+
function startAuthFileLockHeartbeat(lockPath, heartbeatMs) {
|
|
13933
|
+
const heartbeat = setInterval(()=>{
|
|
13934
|
+
const now = new Date();
|
|
13935
|
+
external_fs_.promises.utimes(lockPath, now, now).catch(()=>{});
|
|
13936
|
+
}, heartbeatMs);
|
|
13937
|
+
heartbeat.unref();
|
|
13938
|
+
return heartbeat;
|
|
13939
|
+
}
|
|
13804
13940
|
function decodeKey(b64key) {
|
|
13805
13941
|
const key = Buffer.from(b64key, "base64");
|
|
13806
13942
|
if (32 !== key.length) throw new Error("Encryption key must be a base64-encoded 32-byte key");
|
|
@@ -13845,10 +13981,19 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13845
13981
|
recursive: true
|
|
13846
13982
|
});
|
|
13847
13983
|
const authJson = JSON.stringify(auth, null, 2);
|
|
13848
|
-
|
|
13849
|
-
|
|
13850
|
-
|
|
13851
|
-
|
|
13984
|
+
const tempFilePath = `${authFilePath}.tmp-${external_node_crypto_default().randomBytes(6).toString("hex")}`;
|
|
13985
|
+
try {
|
|
13986
|
+
await external_fs_.promises.writeFile(tempFilePath, encrypt(authJson, encryptionKey), {
|
|
13987
|
+
mode: 384
|
|
13988
|
+
});
|
|
13989
|
+
await external_fs_.promises.chmod(tempFilePath, 448);
|
|
13990
|
+
await external_fs_.promises.rename(tempFilePath, authFilePath);
|
|
13991
|
+
} catch (e) {
|
|
13992
|
+
await external_fs_.promises.rm(tempFilePath, {
|
|
13993
|
+
force: true
|
|
13994
|
+
});
|
|
13995
|
+
throw e;
|
|
13996
|
+
}
|
|
13852
13997
|
await git.raw([
|
|
13853
13998
|
"config",
|
|
13854
13999
|
"--local",
|
|
@@ -13859,6 +14004,7 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13859
14004
|
}
|
|
13860
14005
|
const readAuthFromRepo = async (repoPath)=>{
|
|
13861
14006
|
const git = esm_default(repoPath);
|
|
14007
|
+
if (!await git.checkIsRepo()) return;
|
|
13862
14008
|
const gitDir = await getRepositoryGitDir(repoPath, git);
|
|
13863
14009
|
const authFilePath = getAuthFilePath(gitDir);
|
|
13864
14010
|
if (!external_fs_default().existsSync(authFilePath)) return;
|
|
@@ -13870,6 +14016,7 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13870
14016
|
return resolveAnvilUrl();
|
|
13871
14017
|
}
|
|
13872
14018
|
const ANVIL_SYNC_CLIENT_ID = "anvil-sync";
|
|
14019
|
+
const REFRESH_REQUEST_TIMEOUT_MS = 12000;
|
|
13873
14020
|
let inMemoryAuth = null;
|
|
13874
14021
|
function setInMemoryTokens(anvilUrl, username, tokens) {
|
|
13875
14022
|
inMemoryAuth = {
|
|
@@ -13888,6 +14035,11 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13888
14035
|
function auth_setRepoContext(repoPath) {
|
|
13889
14036
|
repoContext = repoPath;
|
|
13890
14037
|
}
|
|
14038
|
+
async function auth_resolveAuthAnvilUrl() {
|
|
14039
|
+
if (inMemoryAuth) return inMemoryAuth.anvilUrl;
|
|
14040
|
+
const repoAuth = repoContext ? await readAuthFromRepo(repoContext) : void 0;
|
|
14041
|
+
return repoAuth?.anvilUrl ?? resolveAnvilUrl();
|
|
14042
|
+
}
|
|
13891
14043
|
const inFlightRefreshes = new Map();
|
|
13892
14044
|
async function auth_verifyAuth(authToken, anvilUrl = getDefaultAnvilUrl()) {
|
|
13893
14045
|
try {
|
|
@@ -13908,7 +14060,7 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13908
14060
|
throw createAuthError.invalid(`Network error: ${e.message}`);
|
|
13909
14061
|
}
|
|
13910
14062
|
}
|
|
13911
|
-
async function refreshAccessToken(refreshToken, anvilUrl = getDefaultAnvilUrl(), clientId = ANVIL_SYNC_CLIENT_ID) {
|
|
14063
|
+
async function refreshAccessToken(refreshToken, anvilUrl = getDefaultAnvilUrl(), clientId = ANVIL_SYNC_CLIENT_ID, options) {
|
|
13912
14064
|
try {
|
|
13913
14065
|
const tokenResponse = await fetch(`${anvilUrl}/oauth/token`, {
|
|
13914
14066
|
method: "POST",
|
|
@@ -13919,11 +14071,12 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13919
14071
|
grant_type: "refresh_token",
|
|
13920
14072
|
refresh_token: refreshToken,
|
|
13921
14073
|
client_id: clientId
|
|
13922
|
-
})
|
|
14074
|
+
}),
|
|
14075
|
+
signal: AbortSignal.timeout(options?.timeoutMs ?? REFRESH_REQUEST_TIMEOUT_MS)
|
|
13923
14076
|
});
|
|
13924
14077
|
if (!tokenResponse.ok) {
|
|
13925
14078
|
const errorText = await tokenResponse.text();
|
|
13926
|
-
throw createAuthError.refreshFailed(`Failed to refresh token: ${tokenResponse.status} ${errorText}
|
|
14079
|
+
throw createAuthError.refreshFailed(`Failed to refresh token: ${tokenResponse.status} ${errorText}`, tokenResponse.status);
|
|
13927
14080
|
}
|
|
13928
14081
|
const tokenData = await tokenResponse.json();
|
|
13929
14082
|
return tokenData;
|
|
@@ -13940,17 +14093,16 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13940
14093
|
return hasTokens(anvilUrl, username);
|
|
13941
14094
|
}
|
|
13942
14095
|
}
|
|
13943
|
-
async function auth_getValidAuthToken(anvilUrl = getDefaultAnvilUrl(), username) {
|
|
14096
|
+
async function auth_getValidAuthToken(anvilUrl = getDefaultAnvilUrl(), username, options) {
|
|
13944
14097
|
const normalized = config_normalizeAnvilUrl(anvilUrl);
|
|
13945
14098
|
const source = await resolveTokenSource(normalized, username);
|
|
13946
14099
|
const tokens = getSourceTokens(source);
|
|
13947
14100
|
if (!tokens.authToken && !tokens.refreshToken) throw createAuthError.required("Not logged in. Please log in first.");
|
|
13948
|
-
|
|
13949
|
-
if (tokens.refreshToken && isExpired) {
|
|
14101
|
+
if (tokens.refreshToken && isAccessTokenExpired(tokens)) {
|
|
13950
14102
|
const refreshKey = getRefreshKey(normalized, username, source, tokens.refreshToken);
|
|
13951
14103
|
const existingRefresh = inFlightRefreshes.get(refreshKey);
|
|
13952
14104
|
if (existingRefresh) return existingRefresh;
|
|
13953
|
-
const refreshPromise = refreshAndStoreAccessToken(normalized, username, source, tokens.refreshToken).finally(()=>{
|
|
14105
|
+
const refreshPromise = refreshAndStoreAccessToken(normalized, username, source, tokens.refreshToken, options).finally(()=>{
|
|
13954
14106
|
inFlightRefreshes.delete(refreshKey);
|
|
13955
14107
|
});
|
|
13956
14108
|
inFlightRefreshes.set(refreshKey, refreshPromise);
|
|
@@ -13980,6 +14132,9 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13980
14132
|
function getSourceTokens(source) {
|
|
13981
14133
|
return "store" === source.type ? source.tokens : source.auth.tokens;
|
|
13982
14134
|
}
|
|
14135
|
+
function isAccessTokenExpired(tokens) {
|
|
14136
|
+
return null !== tokens.authTokenExpiresAt && tokens.authTokenExpiresAt <= Math.floor(Date.now() / 1000) + 60;
|
|
14137
|
+
}
|
|
13983
14138
|
function getStoreAccountUsername(normalizedUrl, username, refreshToken) {
|
|
13984
14139
|
if (username) return username;
|
|
13985
14140
|
const urlTokens = getUrlTokens(normalizedUrl);
|
|
@@ -13998,11 +14153,43 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13998
14153
|
return `store:${normalizedUrl}:${source.accountUsername ?? username ?? refreshToken}`;
|
|
13999
14154
|
}
|
|
14000
14155
|
}
|
|
14001
|
-
async function refreshAndStoreAccessToken(normalizedUrl, username, source, refreshToken) {
|
|
14156
|
+
async function refreshAndStoreAccessToken(normalizedUrl, username, source, refreshToken, options) {
|
|
14157
|
+
if ("repo" === source.type) return refreshRepoAuthTokens(source.repoPath, {
|
|
14158
|
+
anvilUrl: normalizedUrl,
|
|
14159
|
+
username,
|
|
14160
|
+
auth: source.auth,
|
|
14161
|
+
refreshToken,
|
|
14162
|
+
lock: options?.lock,
|
|
14163
|
+
requestTimeoutMs: options?.requestTimeoutMs
|
|
14164
|
+
});
|
|
14165
|
+
return performTokenRefresh(normalizedUrl, username, source, refreshToken, options?.requestTimeoutMs);
|
|
14166
|
+
}
|
|
14167
|
+
async function refreshRepoAuthTokens(repoPath, options) {
|
|
14168
|
+
const normalizedUrl = config_normalizeAnvilUrl(options.anvilUrl);
|
|
14169
|
+
return withRepoAuthFileLock(repoPath, async ()=>{
|
|
14170
|
+
let auth = options.auth;
|
|
14171
|
+
let refreshToken = options.refreshToken;
|
|
14172
|
+
const current = await readAuthFromRepo(repoPath);
|
|
14173
|
+
if (current && authMatches(current, normalizedUrl, options.username)) {
|
|
14174
|
+
if (current.tokens.authToken && !isAccessTokenExpired(current.tokens)) return current.tokens.authToken;
|
|
14175
|
+
auth = current;
|
|
14176
|
+
refreshToken = current.tokens.refreshToken ?? refreshToken;
|
|
14177
|
+
}
|
|
14178
|
+
if (!auth || !refreshToken) throw createAuthError.required("No repo auth tokens available to refresh.");
|
|
14179
|
+
return performTokenRefresh(normalizedUrl, options.username, {
|
|
14180
|
+
type: "repo",
|
|
14181
|
+
auth,
|
|
14182
|
+
repoPath
|
|
14183
|
+
}, refreshToken, options.requestTimeoutMs);
|
|
14184
|
+
}, options.lock);
|
|
14185
|
+
}
|
|
14186
|
+
async function performTokenRefresh(normalizedUrl, username, source, refreshToken, requestTimeoutMs) {
|
|
14002
14187
|
try {
|
|
14003
14188
|
const tokens = getSourceTokens(source);
|
|
14004
14189
|
const clientId = tokens.clientId ?? ANVIL_SYNC_CLIENT_ID;
|
|
14005
|
-
const tokenData = await refreshAccessToken(refreshToken, normalizedUrl, clientId
|
|
14190
|
+
const tokenData = await refreshAccessToken(refreshToken, normalizedUrl, clientId, {
|
|
14191
|
+
timeoutMs: requestTimeoutMs
|
|
14192
|
+
});
|
|
14006
14193
|
const newTokens = {
|
|
14007
14194
|
authToken: tokenData.access_token,
|
|
14008
14195
|
refreshToken: tokenData.refresh_token,
|
|
@@ -14024,10 +14211,26 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
14024
14211
|
}
|
|
14025
14212
|
return tokenData.access_token;
|
|
14026
14213
|
} catch (e) {
|
|
14214
|
+
if ("repo" === source.type && isRefreshTokenRejection(e)) await clearRepoAuthTokens(source.repoPath, source.auth).catch(()=>{});
|
|
14027
14215
|
await clearTokensForAccount(normalizedUrl, username, refreshToken);
|
|
14028
14216
|
throw e;
|
|
14029
14217
|
}
|
|
14030
14218
|
}
|
|
14219
|
+
function isRefreshTokenRejection(e) {
|
|
14220
|
+
const error = e;
|
|
14221
|
+
return error?.type === "token_refresh_failed" && (400 === error.status || 401 === error.status);
|
|
14222
|
+
}
|
|
14223
|
+
async function clearRepoAuthTokens(repoPath, auth) {
|
|
14224
|
+
const encryptionKey = process.env["ANVIL_AUTH_FILE_ENCRYPTION_KEY"];
|
|
14225
|
+
if (!encryptionKey) return;
|
|
14226
|
+
auth.tokens = {
|
|
14227
|
+
authToken: null,
|
|
14228
|
+
refreshToken: null,
|
|
14229
|
+
authTokenExpiresAt: null,
|
|
14230
|
+
clientId: auth.tokens.clientId
|
|
14231
|
+
};
|
|
14232
|
+
await writeAuthToFile(repoPath, auth, encryptionKey);
|
|
14233
|
+
}
|
|
14031
14234
|
async function clearTokensForAccount(url, username, refreshToken) {
|
|
14032
14235
|
if (inMemoryAuth || repoContext && await readAuthFromRepo(repoContext)) return;
|
|
14033
14236
|
{
|
|
@@ -14109,1042 +14312,1117 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
14109
14312
|
return getAvailableUrls();
|
|
14110
14313
|
}
|
|
14111
14314
|
}
|
|
14112
|
-
|
|
14113
|
-
|
|
14315
|
+
const promises_namespaceObject = require("timers/promises");
|
|
14316
|
+
const WANT_NOT_VALID_RE = /\bwant\s+[0-9a-f]{7,40}\s+not valid\b/i;
|
|
14317
|
+
const FETCH_RETRY_DELAY_MS = 200;
|
|
14318
|
+
function isWantNotValidError(error) {
|
|
14319
|
+
return WANT_NOT_VALID_RE.test(error.message || "");
|
|
14114
14320
|
}
|
|
14115
|
-
|
|
14116
|
-
|
|
14117
|
-
|
|
14118
|
-
|
|
14119
|
-
|
|
14120
|
-
|
|
14121
|
-
|
|
14122
|
-
|
|
14123
|
-
|
|
14124
|
-
|
|
14125
|
-
|
|
14126
|
-
|
|
14127
|
-
|
|
14128
|
-
const data = await resp.json();
|
|
14129
|
-
if (resp.ok) return {
|
|
14130
|
-
valid: data.valid ?? false,
|
|
14131
|
-
app_name: data.app_name
|
|
14132
|
-
};
|
|
14133
|
-
if (401 === resp.status) throw createAuthError.invalid("Authentication failed");
|
|
14134
|
-
if (403 === resp.status) throw createAppError.accessDenied(appId);
|
|
14135
|
-
if (404 === resp.status) throw createAppError.notFound(appId);
|
|
14136
|
-
logger_logger.debug(`validate-app-id failed: ${resp.status} ${resp.statusText}`);
|
|
14137
|
-
return {
|
|
14138
|
-
valid: false,
|
|
14139
|
-
error: data.error || `Server error: ${resp.status}`
|
|
14140
|
-
};
|
|
14141
|
-
} catch (error) {
|
|
14142
|
-
if (error.type) throw error;
|
|
14143
|
-
throw createNetworkError.network(error.message);
|
|
14321
|
+
class git_GitService extends Emitter {
|
|
14322
|
+
git;
|
|
14323
|
+
repoPath;
|
|
14324
|
+
static INDEX_LOCK_RETRY_DELAYS_MS = [
|
|
14325
|
+
25,
|
|
14326
|
+
50,
|
|
14327
|
+
100,
|
|
14328
|
+
200
|
|
14329
|
+
];
|
|
14330
|
+
constructor(repoPath){
|
|
14331
|
+
super();
|
|
14332
|
+
this.repoPath = external_path_default().resolve(repoPath);
|
|
14333
|
+
this.git = esm_default(this.repoPath);
|
|
14144
14334
|
}
|
|
14145
|
-
|
|
14146
|
-
|
|
14147
|
-
|
|
14148
|
-
|
|
14149
|
-
|
|
14150
|
-
|
|
14151
|
-
|
|
14152
|
-
|
|
14153
|
-
|
|
14154
|
-
|
|
14155
|
-
|
|
14156
|
-
|
|
14157
|
-
|
|
14158
|
-
|
|
14159
|
-
|
|
14160
|
-
if (!resp.ok) {
|
|
14161
|
-
if (401 === resp.status) throw createAuthError.invalid("Authentication failed");
|
|
14162
|
-
throw createNetworkError.server(resp.status, resp.statusText);
|
|
14335
|
+
getGit() {
|
|
14336
|
+
return this.git;
|
|
14337
|
+
}
|
|
14338
|
+
getRepoPath() {
|
|
14339
|
+
return this.repoPath;
|
|
14340
|
+
}
|
|
14341
|
+
async getGitDir() {
|
|
14342
|
+
try {
|
|
14343
|
+
const gitDir = (await this.git.revparse([
|
|
14344
|
+
"--git-dir"
|
|
14345
|
+
])).trim();
|
|
14346
|
+
if (!external_path_default().isAbsolute(gitDir)) return external_path_default().resolve(this.repoPath, gitDir);
|
|
14347
|
+
return gitDir;
|
|
14348
|
+
} catch (e) {
|
|
14349
|
+
throw errors_createGitError.commandFailed("rev-parse --git-dir", e.message);
|
|
14163
14350
|
}
|
|
14164
|
-
const data = await resp.json();
|
|
14165
|
-
return data;
|
|
14166
|
-
} catch (error) {
|
|
14167
|
-
if (error.type) throw error;
|
|
14168
|
-
throw createNetworkError.network(error.message);
|
|
14169
14351
|
}
|
|
14170
|
-
|
|
14171
|
-
|
|
14172
|
-
|
|
14173
|
-
|
|
14174
|
-
|
|
14175
|
-
|
|
14176
|
-
|
|
14177
|
-
|
|
14178
|
-
|
|
14179
|
-
|
|
14180
|
-
|
|
14181
|
-
const resp = await fetch(url, {
|
|
14182
|
-
method: "GET",
|
|
14183
|
-
headers: {
|
|
14184
|
-
Authorization: `Bearer ${authToken}`
|
|
14185
|
-
},
|
|
14186
|
-
signal: options.signal
|
|
14187
|
-
});
|
|
14188
|
-
if (!resp.ok) {
|
|
14189
|
-
if (401 === resp.status) throw createAuthError.invalid("Authentication failed");
|
|
14190
|
-
throw createNetworkError.server(resp.status, resp.statusText);
|
|
14352
|
+
async getCurrentBranch() {
|
|
14353
|
+
try {
|
|
14354
|
+
const branchRef = await this.git.revparse([
|
|
14355
|
+
"--abbrev-ref",
|
|
14356
|
+
"HEAD"
|
|
14357
|
+
]);
|
|
14358
|
+
if ("HEAD" === branchRef) throw createSyncError.detachedHead();
|
|
14359
|
+
return branchRef;
|
|
14360
|
+
} catch (e) {
|
|
14361
|
+
if ("detached_head" === e.type) throw e;
|
|
14362
|
+
throw createSyncError.detachedHead();
|
|
14191
14363
|
}
|
|
14192
|
-
const data = await resp.json();
|
|
14193
|
-
return {
|
|
14194
|
-
apps: Array.isArray(data.apps) ? data.apps : [],
|
|
14195
|
-
next_cursor: "string" == typeof data.next_cursor ? data.next_cursor : null
|
|
14196
|
-
};
|
|
14197
|
-
} catch (error) {
|
|
14198
|
-
if (error.type) throw error;
|
|
14199
|
-
throw createNetworkError.network(error.message);
|
|
14200
14364
|
}
|
|
14201
|
-
|
|
14202
|
-
|
|
14203
|
-
|
|
14204
|
-
|
|
14205
|
-
|
|
14206
|
-
|
|
14207
|
-
|
|
14208
|
-
|
|
14209
|
-
|
|
14210
|
-
body: JSON.stringify(payload)
|
|
14211
|
-
});
|
|
14212
|
-
const data = await resp.json();
|
|
14213
|
-
if (401 === resp.status) throw createAuthError.invalid(`Authentication failed (401): ${data.error || "unauthorized"}`);
|
|
14214
|
-
if (403 === resp.status) throw createAuthError.invalid(`Authentication failed (403): ${data.error || "unauthorized"}\n This may indicate:\n - The OAuth token doesn't have permission to write to app ${appId}\n - The app belongs to a different user or organization\n - The OAuth token is missing required scopes (apps:write)`);
|
|
14215
|
-
return {
|
|
14216
|
-
version: data.version,
|
|
14217
|
-
overtaken: data.overtaken,
|
|
14218
|
-
latest_version: data.latest_version,
|
|
14219
|
-
error: 200 !== resp.status ? data.error || `Status ${resp.status}` : void 0
|
|
14220
|
-
};
|
|
14221
|
-
} catch (error) {
|
|
14222
|
-
if (error.type) throw error;
|
|
14223
|
-
throw createNetworkError.network(error.message);
|
|
14365
|
+
async getCommitId() {
|
|
14366
|
+
try {
|
|
14367
|
+
const commitId = (await this.git.revparse([
|
|
14368
|
+
"HEAD"
|
|
14369
|
+
])).trim();
|
|
14370
|
+
return commitId;
|
|
14371
|
+
} catch (e) {
|
|
14372
|
+
throw errors_createGitError.commandFailed("revparse", e.message);
|
|
14373
|
+
}
|
|
14224
14374
|
}
|
|
14225
|
-
|
|
14226
|
-
|
|
14227
|
-
|
|
14228
|
-
|
|
14229
|
-
|
|
14230
|
-
|
|
14231
|
-
|
|
14232
|
-
|
|
14233
|
-
|
|
14234
|
-
|
|
14235
|
-
|
|
14236
|
-
|
|
14237
|
-
|
|
14238
|
-
|
|
14239
|
-
|
|
14240
|
-
|
|
14241
|
-
|
|
14242
|
-
if (!response.ok) return null;
|
|
14243
|
-
const data = await response.json();
|
|
14244
|
-
return data.version;
|
|
14245
|
-
} catch (e) {
|
|
14246
|
-
return null;
|
|
14247
|
-
}
|
|
14248
|
-
}
|
|
14249
|
-
function anvil_api_filterCandidates(candidates, explicitUrl, explicitUsername) {
|
|
14250
|
-
let filtered = candidates;
|
|
14251
|
-
if (explicitUrl) {
|
|
14252
|
-
const normalizedExplicit = config_normalizeAnvilUrl(explicitUrl);
|
|
14253
|
-
filtered = filtered.filter((c)=>c.detectedUrl && config_normalizeAnvilUrl(c.detectedUrl) === normalizedExplicit);
|
|
14254
|
-
}
|
|
14255
|
-
if (explicitUsername) filtered = filtered.filter((c)=>!c.detectedUsername || c.detectedUsername === explicitUsername);
|
|
14256
|
-
return filtered;
|
|
14257
|
-
}
|
|
14258
|
-
function anvil_api_formatCandidateLabel(candidate) {
|
|
14259
|
-
const parts = [
|
|
14260
|
-
candidate.appId
|
|
14261
|
-
];
|
|
14262
|
-
if (candidate.detectedUrl) if (candidate.detectedUsername) parts.push(`(${candidate.detectedUsername} on ${candidate.detectedUrl})`);
|
|
14263
|
-
else parts.push(`(${candidate.detectedUrl})`);
|
|
14264
|
-
parts.push(`- ${candidate.description}`);
|
|
14265
|
-
return parts.join(" ");
|
|
14266
|
-
}
|
|
14267
|
-
function anvil_api_lookupRemoteInfoForAppId(appId, detectedRemotes) {
|
|
14268
|
-
const matches = detectedRemotes.filter((c)=>c.appId === appId);
|
|
14269
|
-
if (0 === matches.length) return {};
|
|
14270
|
-
const withUsername = matches.find((c)=>c.detectedUsername);
|
|
14271
|
-
if (withUsername) return {
|
|
14272
|
-
detectedUrl: withUsername.detectedUrl,
|
|
14273
|
-
detectedUsername: withUsername.detectedUsername
|
|
14274
|
-
};
|
|
14275
|
-
return {
|
|
14276
|
-
detectedUrl: matches[0].detectedUrl,
|
|
14277
|
-
detectedUsername: matches[0].detectedUsername
|
|
14278
|
-
};
|
|
14279
|
-
}
|
|
14280
|
-
async function anvil_api_detectAppIdsFromAllRemotes(repoPath) {
|
|
14281
|
-
const git = esm_default(repoPath);
|
|
14282
|
-
const out = [];
|
|
14283
|
-
try {
|
|
14284
|
-
const remotes = await git.getRemotes(true);
|
|
14285
|
-
for (const remote of remotes){
|
|
14286
|
-
const httpMatch = remote.refs.fetch?.match(/(?:http|https):\/\/(?:[^@]+@)?([^:\/]+)(?::\d+)?\/git\/([A-Z0-9]+)\.git/);
|
|
14287
|
-
if (httpMatch) {
|
|
14288
|
-
const [, host, detectedAppId] = httpMatch;
|
|
14289
|
-
out.push({
|
|
14290
|
-
appId: detectedAppId,
|
|
14291
|
-
source: "remote",
|
|
14292
|
-
description: `Git remote '${remote.name}'`,
|
|
14293
|
-
detectedUrl: config_normalizeAnvilUrl(host)
|
|
14294
|
-
});
|
|
14295
|
-
continue;
|
|
14296
|
-
}
|
|
14297
|
-
const sshMatch = remote.refs.fetch?.match(/ssh:\/\/([^@]+)@([^:]+):(\d+)\/(?:git\/)?([A-Z0-9]+)\.git/);
|
|
14298
|
-
if (sshMatch) {
|
|
14299
|
-
const [, usernamePart, host, , detectedAppId] = sshMatch;
|
|
14300
|
-
const detectedUsername = usernamePart.includes("%") ? decodeURIComponent(usernamePart) : usernamePart;
|
|
14301
|
-
const finalUsername = "git" !== detectedUsername ? detectedUsername : void 0;
|
|
14302
|
-
out.push({
|
|
14303
|
-
appId: detectedAppId,
|
|
14304
|
-
source: "remote",
|
|
14305
|
-
description: `Git remote '${remote.name}' (SSH)`,
|
|
14306
|
-
detectedUrl: config_normalizeAnvilUrl(host),
|
|
14307
|
-
detectedUsername: finalUsername
|
|
14308
|
-
});
|
|
14309
|
-
}
|
|
14310
|
-
}
|
|
14311
|
-
} catch (_e) {}
|
|
14312
|
-
return out;
|
|
14313
|
-
}
|
|
14314
|
-
async function anvil_api_detectAppIdsByCommitLookup(repoPath, options) {
|
|
14315
|
-
const anvilUrl = options.anvilUrl || resolveAnvilUrl();
|
|
14316
|
-
const username = options.username;
|
|
14317
|
-
const git = esm_default(repoPath);
|
|
14318
|
-
const out = [];
|
|
14319
|
-
try {
|
|
14320
|
-
const authToken = await auth_getValidAuthToken(anvilUrl, username);
|
|
14321
|
-
const branchRef = await git.revparse([
|
|
14322
|
-
"--abbrev-ref",
|
|
14323
|
-
"HEAD"
|
|
14324
|
-
]);
|
|
14325
|
-
const currentBranch = "HEAD" === branchRef ? "master" : branchRef;
|
|
14326
|
-
const commitId = (await git.revparse([
|
|
14327
|
-
"HEAD"
|
|
14328
|
-
]))?.trim();
|
|
14329
|
-
if (!commitId) return out;
|
|
14330
|
-
const resp = await fetch(`${anvilUrl}/ide/api/_/apps/lookup-by-commit`, {
|
|
14331
|
-
method: "POST",
|
|
14332
|
-
headers: {
|
|
14333
|
-
Authorization: `Bearer ${authToken}`,
|
|
14334
|
-
"Content-Type": "application/json"
|
|
14335
|
-
},
|
|
14336
|
-
body: JSON.stringify({
|
|
14337
|
-
commit_id: commitId,
|
|
14338
|
-
branch_name: currentBranch
|
|
14339
|
-
})
|
|
14340
|
-
});
|
|
14341
|
-
logger_logger.debug(`Reverse lookup by commit ${commitId} on branch ${currentBranch} returned ${resp.status}`);
|
|
14342
|
-
if (!resp.ok) {
|
|
14343
|
-
const errorBody = await resp.text();
|
|
14344
|
-
logger_logger.debug(`lookup-by-commit error: ${errorBody}`);
|
|
14375
|
+
async getCommitInfo() {
|
|
14376
|
+
try {
|
|
14377
|
+
const hash = (await this.git.revparse([
|
|
14378
|
+
"HEAD"
|
|
14379
|
+
])).trim();
|
|
14380
|
+
const message = (await this.git.raw([
|
|
14381
|
+
"log",
|
|
14382
|
+
"-1",
|
|
14383
|
+
"--format=%s"
|
|
14384
|
+
])).trim();
|
|
14385
|
+
return {
|
|
14386
|
+
hash,
|
|
14387
|
+
shortHash: hash.substring(0, 8),
|
|
14388
|
+
message
|
|
14389
|
+
};
|
|
14390
|
+
} catch (e) {
|
|
14391
|
+
throw errors_createGitError.commandFailed("log", e.message);
|
|
14345
14392
|
}
|
|
14346
|
-
|
|
14347
|
-
|
|
14348
|
-
|
|
14349
|
-
const
|
|
14350
|
-
|
|
14351
|
-
|
|
14352
|
-
|
|
14353
|
-
|
|
14354
|
-
|
|
14393
|
+
}
|
|
14394
|
+
async getStatus() {
|
|
14395
|
+
try {
|
|
14396
|
+
const status = await this.git.status();
|
|
14397
|
+
const staged = status.files.filter((file)=>{
|
|
14398
|
+
const indexStatus = file.index.trim();
|
|
14399
|
+
return indexStatus.length > 0 && "?" !== indexStatus;
|
|
14400
|
+
}).map((file)=>file.path);
|
|
14401
|
+
return {
|
|
14402
|
+
isClean: status.isClean(),
|
|
14403
|
+
modified: status.modified,
|
|
14404
|
+
notAdded: status.not_added,
|
|
14405
|
+
created: status.created,
|
|
14406
|
+
deleted: status.deleted,
|
|
14407
|
+
staged,
|
|
14408
|
+
renamed: status.renamed || []
|
|
14409
|
+
};
|
|
14410
|
+
} catch (e) {
|
|
14411
|
+
throw errors_createGitError.commandFailed("status", e.message);
|
|
14355
14412
|
}
|
|
14356
|
-
} catch (_e) {}
|
|
14357
|
-
return out;
|
|
14358
|
-
}
|
|
14359
|
-
const promises_namespaceObject = require("fs/promises");
|
|
14360
|
-
var promises_default = /*#__PURE__*/ __webpack_require__.n(promises_namespaceObject);
|
|
14361
|
-
function normalizeLineEndings(content) {
|
|
14362
|
-
return content.replace(/\r\n/g, "\n");
|
|
14363
|
-
}
|
|
14364
|
-
function pythonifyName(name) {
|
|
14365
|
-
return name.replace(/[^A-z0-9]/g, "_").replace(/^[0-9]/, "_$&");
|
|
14366
|
-
}
|
|
14367
|
-
function extractPythonName(relativePath, skipParts = 1) {
|
|
14368
|
-
const parts = relativePath.slice(0, -3).split("/");
|
|
14369
|
-
const isPackage = relativePath.endsWith("__init__.py");
|
|
14370
|
-
const relevantParts = isPackage ? parts.slice(skipParts, -1) : parts.slice(skipParts);
|
|
14371
|
-
return relevantParts.map(pythonifyName).join(".");
|
|
14372
|
-
}
|
|
14373
|
-
function deepEqual(a, b) {
|
|
14374
|
-
if (a === b) return true;
|
|
14375
|
-
if (null == a || null == b) return false;
|
|
14376
|
-
if (typeof a !== typeof b) return false;
|
|
14377
|
-
if ("object" != typeof a) return a === b;
|
|
14378
|
-
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
|
14379
|
-
if (Array.isArray(a)) {
|
|
14380
|
-
if (a.length !== b.length) return false;
|
|
14381
|
-
return a.every((item, index)=>deepEqual(item, b[index]));
|
|
14382
14413
|
}
|
|
14383
|
-
|
|
14384
|
-
|
|
14385
|
-
|
|
14386
|
-
|
|
14387
|
-
|
|
14388
|
-
|
|
14389
|
-
|
|
14390
|
-
|
|
14391
|
-
|
|
14392
|
-
|
|
14393
|
-
|
|
14394
|
-
|
|
14395
|
-
return
|
|
14396
|
-
frontmatter,
|
|
14397
|
-
html
|
|
14398
|
-
};
|
|
14414
|
+
async discardModeOnlyChanges(paths) {
|
|
14415
|
+
const discarded = [];
|
|
14416
|
+
for (const relativePath of paths)try {
|
|
14417
|
+
const headMode = await this.getHeadFileMode(relativePath);
|
|
14418
|
+
if ("100644" !== headMode && "100755" !== headMode) continue;
|
|
14419
|
+
const contentUnchanged = await this.hasSameContentAsHead(relativePath);
|
|
14420
|
+
if (!contentUnchanged) continue;
|
|
14421
|
+
await this.restoreExecutableBit(relativePath, "100755" === headMode);
|
|
14422
|
+
discarded.push(relativePath);
|
|
14423
|
+
} catch (e) {
|
|
14424
|
+
throw errors_createGitError.commandFailed("discard mode-only changes", e.message);
|
|
14425
|
+
}
|
|
14426
|
+
return discarded;
|
|
14399
14427
|
}
|
|
14400
|
-
|
|
14401
|
-
|
|
14402
|
-
|
|
14403
|
-
|
|
14404
|
-
|
|
14405
|
-
|
|
14406
|
-
|
|
14407
|
-
|
|
14408
|
-
|
|
14409
|
-
|
|
14410
|
-
|
|
14411
|
-
|
|
14412
|
-
|
|
14413
|
-
|
|
14414
|
-
|
|
14415
|
-
|
|
14416
|
-
|
|
14417
|
-
|
|
14428
|
+
async discardStagedModeOnlyChanges(paths) {
|
|
14429
|
+
const discarded = [];
|
|
14430
|
+
for (const relativePath of paths)try {
|
|
14431
|
+
const headMode = await this.getHeadFileMode(relativePath);
|
|
14432
|
+
if ("100644" !== headMode && "100755" !== headMode) continue;
|
|
14433
|
+
const indexContentUnchanged = await this.hasSameIndexContentAsHead(relativePath);
|
|
14434
|
+
if (!indexContentUnchanged) continue;
|
|
14435
|
+
await this.git.raw([
|
|
14436
|
+
"reset",
|
|
14437
|
+
"-q",
|
|
14438
|
+
"HEAD",
|
|
14439
|
+
"--",
|
|
14440
|
+
relativePath
|
|
14441
|
+
]);
|
|
14442
|
+
await this.restoreExecutableBit(relativePath, "100755" === headMode);
|
|
14443
|
+
discarded.push(relativePath);
|
|
14444
|
+
} catch (e) {
|
|
14445
|
+
throw errors_createGitError.commandFailed("discard staged mode-only changes", e.message);
|
|
14446
|
+
}
|
|
14447
|
+
return discarded;
|
|
14418
14448
|
}
|
|
14419
|
-
|
|
14420
|
-
|
|
14421
|
-
|
|
14422
|
-
|
|
14423
|
-
|
|
14424
|
-
|
|
14425
|
-
|
|
14426
|
-
const
|
|
14427
|
-
|
|
14428
|
-
} catch {}
|
|
14429
|
-
return `${prefix}: ${status} ${errorBody}`;
|
|
14430
|
-
}
|
|
14431
|
-
async function fetchAllDependencies(appId, anvilUrl = resolveAnvilUrl(), options = {}) {
|
|
14432
|
-
const { commit, includeDocs = true, knownDependencies = [] } = options;
|
|
14433
|
-
const token = await auth_getValidAuthToken(anvilUrl);
|
|
14434
|
-
const body = {
|
|
14435
|
-
include_docs: includeDocs,
|
|
14436
|
-
known_dependencies: knownDependencies
|
|
14437
|
-
};
|
|
14438
|
-
if (commit) body.commit = commit;
|
|
14439
|
-
const resp = await fetch(`${anvilUrl}/ide/api/_/apps/${appId}/resolved-dependencies`, {
|
|
14440
|
-
method: "POST",
|
|
14441
|
-
headers: {
|
|
14442
|
-
Authorization: `Bearer ${token}`,
|
|
14443
|
-
"Content-Type": "application/json"
|
|
14444
|
-
},
|
|
14445
|
-
body: JSON.stringify(body)
|
|
14446
|
-
});
|
|
14447
|
-
if (!resp.ok) {
|
|
14448
|
-
const errorBody = await resp.text();
|
|
14449
|
-
throw new Error(formatFetchError("Failed to fetch dependencies", resp.status, errorBody));
|
|
14449
|
+
async getHeadFileMode(relativePath) {
|
|
14450
|
+
const output = await this.git.raw([
|
|
14451
|
+
"ls-tree",
|
|
14452
|
+
"HEAD",
|
|
14453
|
+
"--",
|
|
14454
|
+
relativePath
|
|
14455
|
+
]);
|
|
14456
|
+
const match = output.match(/^(\d{6})\s/);
|
|
14457
|
+
return match?.[1] ?? null;
|
|
14450
14458
|
}
|
|
14451
|
-
|
|
14452
|
-
|
|
14453
|
-
|
|
14454
|
-
|
|
14455
|
-
|
|
14456
|
-
|
|
14457
|
-
|
|
14458
|
-
|
|
14459
|
-
|
|
14460
|
-
|
|
14461
|
-
if (!response.resolved_dependencies.length) {
|
|
14462
|
-
await clearDepsCache(projectRoot);
|
|
14463
|
-
return {
|
|
14464
|
-
response,
|
|
14465
|
-
addedGitignoreEntry: false
|
|
14466
|
-
};
|
|
14459
|
+
async hasSameContentAsHead(relativePath) {
|
|
14460
|
+
const headHash = (await this.git.revparse([
|
|
14461
|
+
`HEAD:${relativePath}`
|
|
14462
|
+
])).trim();
|
|
14463
|
+
const worktreeHash = (await this.git.raw([
|
|
14464
|
+
"hash-object",
|
|
14465
|
+
"--",
|
|
14466
|
+
relativePath
|
|
14467
|
+
])).trim();
|
|
14468
|
+
return headHash === worktreeHash;
|
|
14467
14469
|
}
|
|
14468
|
-
|
|
14469
|
-
|
|
14470
|
-
|
|
14471
|
-
|
|
14472
|
-
|
|
14473
|
-
|
|
14474
|
-
|
|
14475
|
-
|
|
14476
|
-
}
|
|
14477
|
-
function depsDir(projectRoot) {
|
|
14478
|
-
return external_path_default().join(projectRoot, ANVIL_DEPS_DIR);
|
|
14479
|
-
}
|
|
14480
|
-
function depsManifestPath(projectRoot) {
|
|
14481
|
-
return external_path_default().join(depsDir(projectRoot), ANVIL_DEPS_MANIFEST);
|
|
14482
|
-
}
|
|
14483
|
-
function isResolvedDependencyManifestEntry(value) {
|
|
14484
|
-
if (!value || "object" != typeof value) return false;
|
|
14485
|
-
const entry = value;
|
|
14486
|
-
return "string" == typeof entry.app_id && entry.app_id.length > 0 && "string" == typeof entry.commit_id && entry.commit_id.length > 0 && (void 0 === entry.branch || "string" == typeof entry.branch);
|
|
14487
|
-
}
|
|
14488
|
-
function isCachedDependencyManifestEntry(value) {
|
|
14489
|
-
if (!isResolvedDependencyManifestEntry(value)) return false;
|
|
14490
|
-
const entry = value;
|
|
14491
|
-
return "string" == typeof entry.package_name && entry.package_name.length > 0;
|
|
14492
|
-
}
|
|
14493
|
-
function isDepsCacheManifest(value) {
|
|
14494
|
-
if (!value || "object" != typeof value) return false;
|
|
14495
|
-
const manifest = value;
|
|
14496
|
-
return manifest.version === DEPS_MANIFEST_VERSION && "boolean" == typeof manifest.includeDocs && Array.isArray(manifest.source_dependencies) && Array.isArray(manifest.resolved_dependencies) && manifest.resolved_dependencies.every(isResolvedDependencyManifestEntry) && Array.isArray(manifest.cached_dependencies) && manifest.cached_dependencies.every(isCachedDependencyManifestEntry);
|
|
14497
|
-
}
|
|
14498
|
-
async function readDepsCacheManifest(projectRoot) {
|
|
14499
|
-
try {
|
|
14500
|
-
const raw = await promises_default().readFile(depsManifestPath(projectRoot), "utf-8");
|
|
14501
|
-
const parsed = JSON.parse(raw);
|
|
14502
|
-
return isDepsCacheManifest(parsed) ? parsed : void 0;
|
|
14503
|
-
} catch {
|
|
14504
|
-
return;
|
|
14470
|
+
async hasSameIndexContentAsHead(relativePath) {
|
|
14471
|
+
const headHash = (await this.git.revparse([
|
|
14472
|
+
`HEAD:${relativePath}`
|
|
14473
|
+
])).trim();
|
|
14474
|
+
const indexHash = (await this.git.revparse([
|
|
14475
|
+
`:${relativePath}`
|
|
14476
|
+
])).trim();
|
|
14477
|
+
return headHash === indexHash;
|
|
14505
14478
|
}
|
|
14506
|
-
|
|
14507
|
-
|
|
14508
|
-
|
|
14509
|
-
|
|
14510
|
-
|
|
14511
|
-
app_id,
|
|
14512
|
-
commit_id
|
|
14513
|
-
}));
|
|
14514
|
-
}
|
|
14515
|
-
function getDependencyWatchSubscriptionsFromManifest(manifest) {
|
|
14516
|
-
if (!manifest) return [];
|
|
14517
|
-
const cachedByAppId = new Map(manifest.cached_dependencies.map((dep)=>[
|
|
14518
|
-
dep.app_id,
|
|
14519
|
-
dep
|
|
14520
|
-
]));
|
|
14521
|
-
return manifest.resolved_dependencies.flatMap((dep)=>{
|
|
14522
|
-
if (!dep.branch) return [];
|
|
14523
|
-
return [
|
|
14524
|
-
{
|
|
14525
|
-
appId: dep.app_id,
|
|
14526
|
-
branch: dep.branch,
|
|
14527
|
-
packageName: cachedByAppId.get(dep.app_id)?.package_name
|
|
14528
|
-
}
|
|
14529
|
-
];
|
|
14530
|
-
});
|
|
14531
|
-
}
|
|
14532
|
-
function normalizeAnvilYamlDependenciesFromContent(content) {
|
|
14533
|
-
const parsed = external_js_yaml_default().load(content);
|
|
14534
|
-
if (!parsed || "object" != typeof parsed || !Array.isArray(parsed.dependencies)) return [];
|
|
14535
|
-
return normalizeAnvilYamlDependenciesValue(parsed.dependencies);
|
|
14536
|
-
}
|
|
14537
|
-
function normalizeAnvilYamlDependenciesValue(value) {
|
|
14538
|
-
if (!Array.isArray(value)) return [];
|
|
14539
|
-
return value.map(normalizeForComparison);
|
|
14540
|
-
}
|
|
14541
|
-
async function readAnvilYamlDependencies(projectRoot) {
|
|
14542
|
-
try {
|
|
14543
|
-
const content = await promises_default().readFile(external_path_default().join(projectRoot, "anvil.yaml"), "utf-8");
|
|
14544
|
-
return normalizeAnvilYamlDependenciesFromContent(content);
|
|
14545
|
-
} catch {
|
|
14546
|
-
return [];
|
|
14479
|
+
async restoreExecutableBit(relativePath, executable) {
|
|
14480
|
+
const filePath = external_path_default().join(this.repoPath, relativePath);
|
|
14481
|
+
const stat = await external_fs_.promises.stat(filePath);
|
|
14482
|
+
const mode = executable ? 73 | stat.mode : -74 & stat.mode;
|
|
14483
|
+
if ((511 & stat.mode) !== (511 & mode)) await external_fs_.promises.chmod(filePath, mode);
|
|
14547
14484
|
}
|
|
14548
|
-
|
|
14549
|
-
|
|
14550
|
-
|
|
14551
|
-
}
|
|
14552
|
-
function normalizeForComparison(value) {
|
|
14553
|
-
if (Array.isArray(value)) return value.map(normalizeForComparison);
|
|
14554
|
-
if (value && "object" == typeof value) return Object.fromEntries(Object.entries(value).sort(([left], [right])=>left.localeCompare(right)).map(([key, entryValue])=>[
|
|
14555
|
-
key,
|
|
14556
|
-
normalizeForComparison(entryValue)
|
|
14557
|
-
]));
|
|
14558
|
-
return value;
|
|
14559
|
-
}
|
|
14560
|
-
function cachedManifestEntry(dep, packageName) {
|
|
14561
|
-
return {
|
|
14562
|
-
app_id: dep.app_id,
|
|
14563
|
-
commit_id: dep.commit_id,
|
|
14564
|
-
...dep.branch ? {
|
|
14565
|
-
branch: dep.branch
|
|
14566
|
-
} : {},
|
|
14567
|
-
package_name: packageName
|
|
14568
|
-
};
|
|
14569
|
-
}
|
|
14570
|
-
function safeDependencyPath(filePath, kind) {
|
|
14571
|
-
const normalizedPath = external_path_default().normalize(filePath);
|
|
14572
|
-
if (external_path_default().isAbsolute(normalizedPath) || normalizedPath.startsWith("..")) throw new Error(`Invalid dependency ${kind} path: ${filePath}`);
|
|
14573
|
-
return normalizedPath;
|
|
14574
|
-
}
|
|
14575
|
-
function dependencyPythonPath(name, kind) {
|
|
14576
|
-
const parts = name.split(".");
|
|
14577
|
-
if (0 === parts.length || parts.some((part)=>!part || "." === part || ".." === part || part.includes("/") || part.includes("\\"))) throw new Error(`Invalid dependency ${kind} name: ${name}`);
|
|
14578
|
-
return external_path_default().join(...parts);
|
|
14579
|
-
}
|
|
14580
|
-
async function writeDepToCache(projectRoot, dep) {
|
|
14581
|
-
const depDir = external_path_default().join(projectRoot, ANVIL_DEPS_DIR, dep.package_name);
|
|
14582
|
-
await promises_default().rm(depDir, {
|
|
14583
|
-
recursive: true,
|
|
14584
|
-
force: true
|
|
14585
|
-
});
|
|
14586
|
-
await promises_default().mkdir(external_path_default().join(depDir, "client_code"), {
|
|
14587
|
-
recursive: true
|
|
14588
|
-
});
|
|
14589
|
-
await promises_default().mkdir(external_path_default().join(depDir, "server_code"), {
|
|
14590
|
-
recursive: true
|
|
14591
|
-
});
|
|
14592
|
-
await promises_default().writeFile(external_path_default().join(depDir, "anvil.yaml"), external_js_yaml_default().dump({
|
|
14593
|
-
package_name: dep.package_name
|
|
14594
|
-
}));
|
|
14595
|
-
for (const mod of dep.modules ?? []){
|
|
14596
|
-
const modulePath = external_path_default().join(depDir, "client_code", dependencyPythonPath(mod.name, "module"));
|
|
14597
|
-
if (mod.is_package) {
|
|
14598
|
-
await promises_default().mkdir(modulePath, {
|
|
14599
|
-
recursive: true
|
|
14600
|
-
});
|
|
14601
|
-
await promises_default().writeFile(external_path_default().join(modulePath, "__init__.py"), mod.code);
|
|
14602
|
-
} else {
|
|
14603
|
-
const moduleFile = `${modulePath}.py`;
|
|
14604
|
-
await promises_default().mkdir(external_path_default().dirname(moduleFile), {
|
|
14605
|
-
recursive: true
|
|
14606
|
-
});
|
|
14607
|
-
await promises_default().writeFile(moduleFile, mod.code);
|
|
14608
|
-
}
|
|
14485
|
+
async hasUncommittedChanges() {
|
|
14486
|
+
const status = await this.getStatus();
|
|
14487
|
+
return !status.isClean;
|
|
14609
14488
|
}
|
|
14610
|
-
|
|
14611
|
-
|
|
14612
|
-
|
|
14613
|
-
|
|
14614
|
-
|
|
14615
|
-
|
|
14489
|
+
async fetch(url, refSpec) {
|
|
14490
|
+
let attempt = 0;
|
|
14491
|
+
while(true)try {
|
|
14492
|
+
await this.git.fetch([
|
|
14493
|
+
url,
|
|
14494
|
+
refSpec
|
|
14495
|
+
]);
|
|
14496
|
+
if (attempt > 0) this.emit("fetch-retry-resolved", {
|
|
14497
|
+
attempts: attempt,
|
|
14498
|
+
outcome: "succeeded"
|
|
14616
14499
|
});
|
|
14617
|
-
|
|
14618
|
-
|
|
14619
|
-
|
|
14620
|
-
|
|
14621
|
-
|
|
14622
|
-
|
|
14500
|
+
return;
|
|
14501
|
+
} catch (e) {
|
|
14502
|
+
const err = e;
|
|
14503
|
+
if (!isWantNotValidError(err)) {
|
|
14504
|
+
if (attempt > 0) this.emit("fetch-retry-resolved", {
|
|
14505
|
+
attempts: attempt,
|
|
14506
|
+
outcome: "failed"
|
|
14507
|
+
});
|
|
14508
|
+
throw errors_createGitError.fetchFailed(err.message);
|
|
14509
|
+
}
|
|
14510
|
+
attempt++;
|
|
14511
|
+
this.emit("fetch-retry", {
|
|
14512
|
+
attempt,
|
|
14513
|
+
delayMs: FETCH_RETRY_DELAY_MS,
|
|
14514
|
+
error: err.message
|
|
14623
14515
|
});
|
|
14624
|
-
|
|
14625
|
-
await
|
|
14516
|
+
logger_logger.verbose(`git fetch race (attempt ${attempt}, sleeping ${FETCH_RETRY_DELAY_MS}ms): ${err.message}`);
|
|
14517
|
+
await (0, promises_namespaceObject.setTimeout)(FETCH_RETRY_DELAY_MS);
|
|
14626
14518
|
}
|
|
14627
14519
|
}
|
|
14628
|
-
|
|
14629
|
-
|
|
14630
|
-
|
|
14631
|
-
|
|
14632
|
-
|
|
14633
|
-
|
|
14634
|
-
|
|
14635
|
-
|
|
14636
|
-
|
|
14637
|
-
|
|
14638
|
-
|
|
14639
|
-
|
|
14640
|
-
await
|
|
14520
|
+
async reset(ref, mode = "mixed") {
|
|
14521
|
+
await this.runGitCommandWithIndexLockRetry("reset", ()=>this.git.reset([
|
|
14522
|
+
`--${mode}`,
|
|
14523
|
+
ref
|
|
14524
|
+
]));
|
|
14525
|
+
}
|
|
14526
|
+
async checkout(paths) {
|
|
14527
|
+
await this.runGitCommandWithIndexLockRetry("checkout", ()=>this.git.checkout(paths));
|
|
14528
|
+
}
|
|
14529
|
+
async runGitCommandWithIndexLockRetry(command, operation) {
|
|
14530
|
+
let lastError;
|
|
14531
|
+
for(let attempt = 0; attempt <= git_GitService.INDEX_LOCK_RETRY_DELAYS_MS.length; attempt += 1)try {
|
|
14532
|
+
await operation();
|
|
14533
|
+
return;
|
|
14534
|
+
} catch (e) {
|
|
14535
|
+
lastError = e;
|
|
14536
|
+
if (!this.isIndexLockError(e) || attempt === git_GitService.INDEX_LOCK_RETRY_DELAYS_MS.length) throw errors_createGitError.commandFailed(command, e.message);
|
|
14537
|
+
await (0, promises_namespaceObject.setTimeout)(git_GitService.INDEX_LOCK_RETRY_DELAYS_MS[attempt]);
|
|
14641
14538
|
}
|
|
14539
|
+
throw errors_createGitError.commandFailed(command, lastError.message);
|
|
14642
14540
|
}
|
|
14643
|
-
|
|
14644
|
-
const
|
|
14645
|
-
|
|
14646
|
-
recursive: true
|
|
14647
|
-
});
|
|
14648
|
-
await promises_default().writeFile(targetPath, Buffer.from(asset.content, "base64"));
|
|
14541
|
+
isIndexLockError(error) {
|
|
14542
|
+
const message = error.message ?? "";
|
|
14543
|
+
return message.includes("Unable to create") && message.includes("index.lock") && message.includes("File exists");
|
|
14649
14544
|
}
|
|
14650
|
-
|
|
14651
|
-
|
|
14652
|
-
|
|
14653
|
-
|
|
14654
|
-
|
|
14655
|
-
|
|
14545
|
+
async stash(message) {
|
|
14546
|
+
try {
|
|
14547
|
+
const args = [
|
|
14548
|
+
"stash",
|
|
14549
|
+
"push",
|
|
14550
|
+
"--include-untracked"
|
|
14551
|
+
];
|
|
14552
|
+
if (message) args.push("-m", message);
|
|
14553
|
+
const result = await this.git.raw(args);
|
|
14554
|
+
return !result.includes("No local changes to save");
|
|
14555
|
+
} catch (e) {
|
|
14556
|
+
throw errors_createGitError.commandFailed("stash", e.message);
|
|
14557
|
+
}
|
|
14656
14558
|
}
|
|
14657
|
-
|
|
14658
|
-
|
|
14659
|
-
|
|
14660
|
-
|
|
14661
|
-
|
|
14662
|
-
|
|
14663
|
-
|
|
14664
|
-
|
|
14665
|
-
|
|
14666
|
-
recursive: true,
|
|
14667
|
-
force: true
|
|
14668
|
-
});
|
|
14669
|
-
for (const dep of response.dependencies)await writeDepToCache(projectRoot, dep);
|
|
14670
|
-
const returnedByAppId = new Map(response.dependencies.map((dep)=>[
|
|
14671
|
-
dep.app_id,
|
|
14672
|
-
dep
|
|
14673
|
-
]));
|
|
14674
|
-
const previousByAppId = new Map(previousCached.map((dep)=>[
|
|
14675
|
-
dep.app_id,
|
|
14676
|
-
dep
|
|
14677
|
-
]));
|
|
14678
|
-
const cachedDependencies = response.resolved_dependencies.map((dep)=>{
|
|
14679
|
-
const returned = returnedByAppId.get(dep.app_id);
|
|
14680
|
-
if (returned) return cachedManifestEntry(returned, returned.package_name);
|
|
14681
|
-
const previous = previousByAppId.get(dep.app_id);
|
|
14682
|
-
if (!previous) return;
|
|
14683
|
-
return cachedManifestEntry(dep, previous.package_name);
|
|
14684
|
-
}).filter((dep)=>void 0 !== dep);
|
|
14685
|
-
const newManifest = {
|
|
14686
|
-
version: DEPS_MANIFEST_VERSION,
|
|
14687
|
-
includeDocs,
|
|
14688
|
-
source_dependencies: await readAnvilYamlDependencies(projectRoot),
|
|
14689
|
-
resolved_dependencies: response.resolved_dependencies,
|
|
14690
|
-
cached_dependencies: cachedDependencies
|
|
14691
|
-
};
|
|
14692
|
-
await promises_default().mkdir(depsDir(projectRoot), {
|
|
14693
|
-
recursive: true
|
|
14694
|
-
});
|
|
14695
|
-
await promises_default().writeFile(depsManifestPath(projectRoot), `${JSON.stringify(newManifest, null, 2)}\n`);
|
|
14696
|
-
}
|
|
14697
|
-
async function clearDepsCache(projectRoot) {
|
|
14698
|
-
await promises_default().rm(depsDir(projectRoot), {
|
|
14699
|
-
recursive: true,
|
|
14700
|
-
force: true
|
|
14701
|
-
});
|
|
14702
|
-
}
|
|
14703
|
-
const external_timers_promises_namespaceObject = require("timers/promises");
|
|
14704
|
-
const WANT_NOT_VALID_RE = /\bwant\s+[0-9a-f]{7,40}\s+not valid\b/i;
|
|
14705
|
-
const FETCH_RETRY_DELAY_MS = 200;
|
|
14706
|
-
function isWantNotValidError(error) {
|
|
14707
|
-
return WANT_NOT_VALID_RE.test(error.message || "");
|
|
14708
|
-
}
|
|
14709
|
-
class git_GitService extends Emitter {
|
|
14710
|
-
git;
|
|
14711
|
-
repoPath;
|
|
14712
|
-
static INDEX_LOCK_RETRY_DELAYS_MS = [
|
|
14713
|
-
25,
|
|
14714
|
-
50,
|
|
14715
|
-
100,
|
|
14716
|
-
200
|
|
14717
|
-
];
|
|
14718
|
-
constructor(repoPath){
|
|
14719
|
-
super();
|
|
14720
|
-
this.repoPath = external_path_default().resolve(repoPath);
|
|
14721
|
-
this.git = esm_default(this.repoPath);
|
|
14559
|
+
async stashPop() {
|
|
14560
|
+
try {
|
|
14561
|
+
await this.git.raw([
|
|
14562
|
+
"stash",
|
|
14563
|
+
"pop"
|
|
14564
|
+
]);
|
|
14565
|
+
} catch (e) {
|
|
14566
|
+
throw errors_createGitError.commandFailed("stash pop", e.message);
|
|
14567
|
+
}
|
|
14722
14568
|
}
|
|
14723
|
-
|
|
14724
|
-
|
|
14569
|
+
async clean(files) {
|
|
14570
|
+
try {
|
|
14571
|
+
await this.git.clean(CleanOptions.FORCE, files);
|
|
14572
|
+
} catch (e) {
|
|
14573
|
+
throw errors_createGitError.commandFailed("clean", e.message);
|
|
14574
|
+
}
|
|
14725
14575
|
}
|
|
14726
|
-
|
|
14727
|
-
|
|
14576
|
+
async diffNames(fromCommit, toCommit) {
|
|
14577
|
+
try {
|
|
14578
|
+
const diffResult = await this.git.diff([
|
|
14579
|
+
fromCommit,
|
|
14580
|
+
toCommit,
|
|
14581
|
+
"--name-only"
|
|
14582
|
+
]);
|
|
14583
|
+
const files = diffResult.split("\n").filter((f)=>f.trim());
|
|
14584
|
+
return files;
|
|
14585
|
+
} catch (e) {
|
|
14586
|
+
throw errors_createGitError.commandFailed("diff", e.message);
|
|
14587
|
+
}
|
|
14728
14588
|
}
|
|
14729
|
-
async
|
|
14589
|
+
async getAheadBehind(localRef, remoteRef) {
|
|
14730
14590
|
try {
|
|
14731
|
-
const
|
|
14732
|
-
"
|
|
14733
|
-
|
|
14734
|
-
|
|
14735
|
-
|
|
14591
|
+
const result = await this.git.raw([
|
|
14592
|
+
"rev-list",
|
|
14593
|
+
"--left-right",
|
|
14594
|
+
"--count",
|
|
14595
|
+
`${remoteRef}...${localRef}`
|
|
14596
|
+
]);
|
|
14597
|
+
const [behind, ahead] = result.trim().split("\t").map(Number);
|
|
14598
|
+
return {
|
|
14599
|
+
ahead,
|
|
14600
|
+
behind
|
|
14601
|
+
};
|
|
14736
14602
|
} catch (e) {
|
|
14737
|
-
throw errors_createGitError.commandFailed("rev-
|
|
14603
|
+
throw errors_createGitError.commandFailed("rev-list", e.message);
|
|
14738
14604
|
}
|
|
14739
14605
|
}
|
|
14740
|
-
async
|
|
14606
|
+
async show(refPath) {
|
|
14741
14607
|
try {
|
|
14742
|
-
const
|
|
14743
|
-
|
|
14744
|
-
"HEAD"
|
|
14608
|
+
const content = await this.git.show([
|
|
14609
|
+
refPath
|
|
14745
14610
|
]);
|
|
14746
|
-
|
|
14747
|
-
return branchRef;
|
|
14611
|
+
return content;
|
|
14748
14612
|
} catch (e) {
|
|
14749
|
-
|
|
14750
|
-
throw createSyncError.detachedHead();
|
|
14613
|
+
throw errors_createGitError.commandFailed("show", e.message);
|
|
14751
14614
|
}
|
|
14752
14615
|
}
|
|
14753
|
-
async
|
|
14616
|
+
async push(url, refSpec, force = false) {
|
|
14754
14617
|
try {
|
|
14755
|
-
const
|
|
14756
|
-
"
|
|
14757
|
-
|
|
14758
|
-
|
|
14618
|
+
const args = force ? [
|
|
14619
|
+
"push",
|
|
14620
|
+
"--force",
|
|
14621
|
+
url,
|
|
14622
|
+
refSpec
|
|
14623
|
+
] : [
|
|
14624
|
+
"push",
|
|
14625
|
+
url,
|
|
14626
|
+
refSpec
|
|
14627
|
+
];
|
|
14628
|
+
await this.git.raw(args);
|
|
14759
14629
|
} catch (e) {
|
|
14760
|
-
throw errors_createGitError.commandFailed("
|
|
14630
|
+
throw errors_createGitError.commandFailed("push", e.message);
|
|
14761
14631
|
}
|
|
14762
14632
|
}
|
|
14763
|
-
async
|
|
14633
|
+
async rebase(onto) {
|
|
14764
14634
|
try {
|
|
14765
|
-
|
|
14766
|
-
"
|
|
14767
|
-
|
|
14768
|
-
|
|
14769
|
-
|
|
14770
|
-
|
|
14771
|
-
|
|
14772
|
-
|
|
14773
|
-
|
|
14774
|
-
|
|
14775
|
-
|
|
14776
|
-
|
|
14777
|
-
|
|
14635
|
+
await this.git.raw([
|
|
14636
|
+
"rebase",
|
|
14637
|
+
onto
|
|
14638
|
+
]);
|
|
14639
|
+
} catch (e) {
|
|
14640
|
+
throw errors_createGitError.commandFailed("rebase", e.message);
|
|
14641
|
+
}
|
|
14642
|
+
}
|
|
14643
|
+
async rebaseAbort() {
|
|
14644
|
+
try {
|
|
14645
|
+
await this.git.raw([
|
|
14646
|
+
"rebase",
|
|
14647
|
+
"--abort"
|
|
14648
|
+
]);
|
|
14778
14649
|
} catch (e) {
|
|
14779
|
-
throw errors_createGitError.commandFailed("
|
|
14650
|
+
throw errors_createGitError.commandFailed("rebase --abort", e.message);
|
|
14780
14651
|
}
|
|
14781
14652
|
}
|
|
14782
|
-
async
|
|
14653
|
+
async isAncestor(ancestorRef, descendantRef) {
|
|
14783
14654
|
try {
|
|
14784
|
-
const
|
|
14785
|
-
|
|
14786
|
-
|
|
14787
|
-
|
|
14788
|
-
|
|
14789
|
-
|
|
14790
|
-
|
|
14791
|
-
|
|
14792
|
-
|
|
14793
|
-
|
|
14794
|
-
|
|
14795
|
-
staged,
|
|
14796
|
-
renamed: status.renamed || []
|
|
14797
|
-
};
|
|
14798
|
-
} catch (e) {
|
|
14799
|
-
throw errors_createGitError.commandFailed("status", e.message);
|
|
14655
|
+
const mergeBase = (await this.git.raw([
|
|
14656
|
+
"merge-base",
|
|
14657
|
+
ancestorRef,
|
|
14658
|
+
descendantRef
|
|
14659
|
+
])).trim();
|
|
14660
|
+
const ancestorCommit = (await this.git.revparse([
|
|
14661
|
+
ancestorRef
|
|
14662
|
+
])).trim();
|
|
14663
|
+
return mergeBase === ancestorCommit;
|
|
14664
|
+
} catch {
|
|
14665
|
+
return false;
|
|
14800
14666
|
}
|
|
14801
14667
|
}
|
|
14802
|
-
async
|
|
14803
|
-
|
|
14804
|
-
|
|
14805
|
-
|
|
14806
|
-
|
|
14807
|
-
|
|
14808
|
-
if (!contentUnchanged) continue;
|
|
14809
|
-
await this.restoreExecutableBit(relativePath, "100755" === headMode);
|
|
14810
|
-
discarded.push(relativePath);
|
|
14811
|
-
} catch (e) {
|
|
14812
|
-
throw errors_createGitError.commandFailed("discard mode-only changes", e.message);
|
|
14813
|
-
}
|
|
14814
|
-
return discarded;
|
|
14668
|
+
async mergeFastForward(ref) {
|
|
14669
|
+
await this.runGitCommandWithIndexLockRetry("merge --ff-only", ()=>this.git.raw([
|
|
14670
|
+
"merge",
|
|
14671
|
+
"--ff-only",
|
|
14672
|
+
ref
|
|
14673
|
+
]));
|
|
14815
14674
|
}
|
|
14816
|
-
async
|
|
14817
|
-
|
|
14818
|
-
for (const relativePath of paths)try {
|
|
14819
|
-
const headMode = await this.getHeadFileMode(relativePath);
|
|
14820
|
-
if ("100644" !== headMode && "100755" !== headMode) continue;
|
|
14821
|
-
const indexContentUnchanged = await this.hasSameIndexContentAsHead(relativePath);
|
|
14822
|
-
if (!indexContentUnchanged) continue;
|
|
14675
|
+
async deleteRef(ref) {
|
|
14676
|
+
try {
|
|
14823
14677
|
await this.git.raw([
|
|
14824
|
-
"
|
|
14825
|
-
"-
|
|
14826
|
-
|
|
14827
|
-
"--",
|
|
14828
|
-
relativePath
|
|
14678
|
+
"update-ref",
|
|
14679
|
+
"-d",
|
|
14680
|
+
ref
|
|
14829
14681
|
]);
|
|
14830
|
-
|
|
14831
|
-
|
|
14682
|
+
} catch (e) {}
|
|
14683
|
+
}
|
|
14684
|
+
async getRemotes() {
|
|
14685
|
+
try {
|
|
14686
|
+
const remotes = await this.git.getRemotes(true);
|
|
14687
|
+
return remotes.map((r)=>({
|
|
14688
|
+
name: r.name,
|
|
14689
|
+
fetchUrl: r.refs.fetch
|
|
14690
|
+
}));
|
|
14832
14691
|
} catch (e) {
|
|
14833
|
-
throw errors_createGitError.commandFailed("
|
|
14692
|
+
throw errors_createGitError.commandFailed("remote", e.message);
|
|
14834
14693
|
}
|
|
14835
|
-
return discarded;
|
|
14836
14694
|
}
|
|
14837
|
-
async
|
|
14838
|
-
const
|
|
14839
|
-
|
|
14840
|
-
"HEAD",
|
|
14841
|
-
"--",
|
|
14842
|
-
relativePath
|
|
14843
|
-
]);
|
|
14844
|
-
const match = output.match(/^(\d{6})\s/);
|
|
14845
|
-
return match?.[1] ?? null;
|
|
14695
|
+
async isGitInitialized() {
|
|
14696
|
+
const gitPath = external_path_default().join(this.repoPath, ".git");
|
|
14697
|
+
return external_fs_.existsSync(gitPath);
|
|
14846
14698
|
}
|
|
14847
|
-
async
|
|
14848
|
-
const
|
|
14849
|
-
|
|
14850
|
-
|
|
14851
|
-
|
|
14852
|
-
|
|
14853
|
-
|
|
14854
|
-
|
|
14855
|
-
|
|
14856
|
-
|
|
14699
|
+
async removeEmptyDirectories(removedFiles) {
|
|
14700
|
+
const directoriesToCheck = new Set();
|
|
14701
|
+
for (const file of removedFiles){
|
|
14702
|
+
let dir = external_path_default().dirname(file);
|
|
14703
|
+
while(dir && "." !== dir){
|
|
14704
|
+
directoriesToCheck.add(dir);
|
|
14705
|
+
const parentDir = external_path_default().dirname(dir);
|
|
14706
|
+
if (parentDir === dir) break;
|
|
14707
|
+
dir = parentDir;
|
|
14708
|
+
}
|
|
14709
|
+
}
|
|
14710
|
+
const sortedDirs = Array.from(directoriesToCheck).sort((a, b)=>b.split("/").length - a.split("/").length);
|
|
14711
|
+
for (const dir of sortedDirs)try {
|
|
14712
|
+
const dirPath = external_path_default().join(this.repoPath, dir);
|
|
14713
|
+
if (!external_fs_.existsSync(dirPath)) continue;
|
|
14714
|
+
const entries = await external_fs_.promises.readdir(dirPath);
|
|
14715
|
+
if (0 === entries.length) await external_fs_.promises.rmdir(dirPath);
|
|
14716
|
+
} catch (error) {}
|
|
14717
|
+
}
|
|
14718
|
+
}
|
|
14719
|
+
async function getStagedFileChanges(git, gitService) {
|
|
14720
|
+
try {
|
|
14721
|
+
const status = await git.status();
|
|
14722
|
+
const renames = status.renamed || [];
|
|
14723
|
+
const stagedFiles = status.files.filter((f)=>" " !== f.index && "?" !== f.index);
|
|
14724
|
+
const stagedModeOnlyPaths = new Set(gitService ? await gitService.discardStagedModeOnlyChanges(stagedFiles.filter((f)=>"R" !== f.index && "D" !== f.index).map((f)=>f.path)) : []);
|
|
14725
|
+
const stagedRenames = [];
|
|
14726
|
+
for (const f of stagedFiles)if ("R" === f.index) {
|
|
14727
|
+
const rename = renames.find((r)=>r.to === f.path);
|
|
14728
|
+
if (rename) stagedRenames.push({
|
|
14729
|
+
path: rename.to,
|
|
14730
|
+
type: "rename",
|
|
14731
|
+
from: rename.from
|
|
14732
|
+
});
|
|
14733
|
+
}
|
|
14734
|
+
const stagedRenamedFromPaths = new Set(stagedRenames.map((r)=>r.from));
|
|
14735
|
+
const stagedRenamedToPaths = new Set(stagedRenames.map((r)=>r.path));
|
|
14736
|
+
const changes = [];
|
|
14737
|
+
for (const f of stagedFiles){
|
|
14738
|
+
if ("R" !== f.index) {
|
|
14739
|
+
if (!stagedModeOnlyPaths.has(f.path)) {
|
|
14740
|
+
if (!(stagedRenamedFromPaths.has(f.path) || stagedRenamedToPaths.has(f.path))) if ("D" === f.index) changes.push({
|
|
14741
|
+
path: f.path,
|
|
14742
|
+
type: "unlink"
|
|
14743
|
+
});
|
|
14744
|
+
else if ("A" === f.index || "?" === f.index) changes.push({
|
|
14745
|
+
path: f.path,
|
|
14746
|
+
type: "add"
|
|
14747
|
+
});
|
|
14748
|
+
else changes.push({
|
|
14749
|
+
path: f.path,
|
|
14750
|
+
type: "change"
|
|
14751
|
+
});
|
|
14752
|
+
}
|
|
14753
|
+
}
|
|
14754
|
+
}
|
|
14755
|
+
changes.push(...stagedRenames);
|
|
14756
|
+
return changes;
|
|
14757
|
+
} catch (e) {
|
|
14758
|
+
throw errors_createGitError.commandFailed("status", e.message);
|
|
14759
|
+
}
|
|
14760
|
+
}
|
|
14761
|
+
async function git_getCurrentOrFallbackBranchName(git) {
|
|
14762
|
+
const branchRef = (await git.revparse([
|
|
14763
|
+
"--abbrev-ref",
|
|
14764
|
+
"HEAD"
|
|
14765
|
+
])).trim();
|
|
14766
|
+
if ("HEAD" !== branchRef) return branchRef;
|
|
14767
|
+
const [localBranches, remoteBranches] = await Promise.all([
|
|
14768
|
+
git.raw([
|
|
14769
|
+
"branch",
|
|
14770
|
+
"--format=%(refname:short)",
|
|
14771
|
+
"--contains",
|
|
14772
|
+
"HEAD"
|
|
14773
|
+
]),
|
|
14774
|
+
git.raw([
|
|
14775
|
+
"branch",
|
|
14776
|
+
"-r",
|
|
14777
|
+
"--format=%(refname:short)",
|
|
14778
|
+
"--contains",
|
|
14779
|
+
"HEAD"
|
|
14780
|
+
])
|
|
14781
|
+
]);
|
|
14782
|
+
const branchNames = [
|
|
14783
|
+
...parseBranchList(localBranches),
|
|
14784
|
+
...parseBranchList(remoteBranches).filter((branchName)=>!branchName.endsWith("/HEAD")).map((branchName)=>branchName.replace(/^[^/]+\//, ""))
|
|
14785
|
+
];
|
|
14786
|
+
const branchSet = new Set(branchNames);
|
|
14787
|
+
if (branchSet.has("master")) return "master";
|
|
14788
|
+
if (branchSet.has("main")) return "main";
|
|
14789
|
+
return "master";
|
|
14790
|
+
}
|
|
14791
|
+
function parseBranchList(output) {
|
|
14792
|
+
return output.split(/\r?\n/).map((line)=>line.trim()).filter(Boolean);
|
|
14793
|
+
}
|
|
14794
|
+
function anvil_api_getDefaultAnvilUrl() {
|
|
14795
|
+
return resolveAnvilUrl();
|
|
14796
|
+
}
|
|
14797
|
+
async function createAnvilApp(options) {
|
|
14798
|
+
let response;
|
|
14799
|
+
try {
|
|
14800
|
+
response = await fetch(`${options.anvilUrl}/ide/api/_/apps`, {
|
|
14801
|
+
method: "POST",
|
|
14802
|
+
headers: {
|
|
14803
|
+
Authorization: `Bearer ${options.authToken}`,
|
|
14804
|
+
"Content-Type": "application/json"
|
|
14805
|
+
},
|
|
14806
|
+
body: JSON.stringify({
|
|
14807
|
+
name: options.name,
|
|
14808
|
+
tags: options.tags
|
|
14809
|
+
})
|
|
14810
|
+
});
|
|
14811
|
+
} catch (error) {
|
|
14812
|
+
throw createNetworkError.network(error.message);
|
|
14813
|
+
}
|
|
14814
|
+
const data = await response.json().catch(()=>({}));
|
|
14815
|
+
if (!response.ok) {
|
|
14816
|
+
if (401 === response.status || 403 === response.status) throw createAuthError.invalid(data.error || "Not authorized to create an app");
|
|
14817
|
+
throw new Error(data.error || `Failed to create app: ${response.status} ${response.statusText}`);
|
|
14818
|
+
}
|
|
14819
|
+
if ("string" != typeof data.id || !data.id) throw new Error("App creation response did not contain an app ID.");
|
|
14820
|
+
return {
|
|
14821
|
+
id: data.id,
|
|
14822
|
+
..."string" == typeof data.name ? {
|
|
14823
|
+
name: data.name
|
|
14824
|
+
} : {},
|
|
14825
|
+
...data.tags ? {
|
|
14826
|
+
tags: data.tags
|
|
14827
|
+
} : {}
|
|
14828
|
+
};
|
|
14829
|
+
}
|
|
14830
|
+
async function anvil_api_validateAppId(appId, anvilUrl = anvil_api_getDefaultAnvilUrl(), username) {
|
|
14831
|
+
const authToken = await auth_getValidAuthToken(anvilUrl, username);
|
|
14832
|
+
try {
|
|
14833
|
+
const resp = await fetch(`${anvilUrl}/ide/api/_/apps/validate-app-id`, {
|
|
14834
|
+
method: "POST",
|
|
14835
|
+
headers: {
|
|
14836
|
+
Authorization: `Bearer ${authToken}`,
|
|
14837
|
+
"Content-Type": "application/json"
|
|
14838
|
+
},
|
|
14839
|
+
body: JSON.stringify({
|
|
14840
|
+
app_id: appId
|
|
14841
|
+
})
|
|
14842
|
+
});
|
|
14843
|
+
const data = await resp.json();
|
|
14844
|
+
if (resp.ok) return {
|
|
14845
|
+
valid: data.valid ?? false,
|
|
14846
|
+
app_name: data.app_name
|
|
14847
|
+
};
|
|
14848
|
+
if (401 === resp.status) throw createAuthError.invalid("Authentication failed");
|
|
14849
|
+
if (403 === resp.status) throw createAppError.accessDenied(appId);
|
|
14850
|
+
if (404 === resp.status) throw createAppError.notFound(appId);
|
|
14851
|
+
logger_logger.debug(`validate-app-id failed: ${resp.status} ${resp.statusText}`);
|
|
14852
|
+
return {
|
|
14853
|
+
valid: false,
|
|
14854
|
+
error: data.error || `Server error: ${resp.status}`
|
|
14855
|
+
};
|
|
14856
|
+
} catch (error) {
|
|
14857
|
+
if (error.type) throw error;
|
|
14858
|
+
throw createNetworkError.network(error.message);
|
|
14859
|
+
}
|
|
14860
|
+
}
|
|
14861
|
+
async function lookupByCommit(commitId, branchName, anvilUrl = anvil_api_getDefaultAnvilUrl(), username) {
|
|
14862
|
+
const authToken = await auth_getValidAuthToken(anvilUrl, username);
|
|
14863
|
+
try {
|
|
14864
|
+
const resp = await fetch(`${anvilUrl}/ide/api/_/apps/lookup-by-commit`, {
|
|
14865
|
+
method: "POST",
|
|
14866
|
+
headers: {
|
|
14867
|
+
Authorization: `Bearer ${authToken}`,
|
|
14868
|
+
"Content-Type": "application/json"
|
|
14869
|
+
},
|
|
14870
|
+
body: JSON.stringify({
|
|
14871
|
+
commit_id: commitId,
|
|
14872
|
+
branch_name: branchName
|
|
14873
|
+
})
|
|
14874
|
+
});
|
|
14875
|
+
if (!resp.ok) {
|
|
14876
|
+
if (401 === resp.status) throw createAuthError.invalid("Authentication failed");
|
|
14877
|
+
throw createNetworkError.server(resp.status, resp.statusText);
|
|
14878
|
+
}
|
|
14879
|
+
const data = await resp.json();
|
|
14880
|
+
return data;
|
|
14881
|
+
} catch (error) {
|
|
14882
|
+
if (error.type) throw error;
|
|
14883
|
+
throw createNetworkError.network(error.message);
|
|
14884
|
+
}
|
|
14885
|
+
}
|
|
14886
|
+
async function listAppsForCheckout(options = {}) {
|
|
14887
|
+
const anvilUrl = options.anvilUrl ?? anvil_api_getDefaultAnvilUrl();
|
|
14888
|
+
const authToken = await auth_getValidAuthToken(anvilUrl, options.username);
|
|
14889
|
+
const params = new URLSearchParams();
|
|
14890
|
+
if ("number" == typeof options.limit) params.set("limit", String(options.limit));
|
|
14891
|
+
if (options.cursor) params.set("cursor", options.cursor);
|
|
14892
|
+
if (options.q && options.q.trim()) params.set("q", options.q.trim());
|
|
14893
|
+
const query = params.toString();
|
|
14894
|
+
const url = `${anvilUrl}/ide/api/_/apps${query ? `?${query}` : ""}`;
|
|
14895
|
+
try {
|
|
14896
|
+
const resp = await fetch(url, {
|
|
14897
|
+
method: "GET",
|
|
14898
|
+
headers: {
|
|
14899
|
+
Authorization: `Bearer ${authToken}`
|
|
14900
|
+
},
|
|
14901
|
+
signal: options.signal
|
|
14902
|
+
});
|
|
14903
|
+
if (!resp.ok) {
|
|
14904
|
+
if (401 === resp.status) throw createAuthError.invalid("Authentication failed");
|
|
14905
|
+
throw createNetworkError.server(resp.status, resp.statusText);
|
|
14906
|
+
}
|
|
14907
|
+
const data = await resp.json();
|
|
14908
|
+
return {
|
|
14909
|
+
apps: Array.isArray(data.apps) ? data.apps : [],
|
|
14910
|
+
next_cursor: "string" == typeof data.next_cursor ? data.next_cursor : null
|
|
14911
|
+
};
|
|
14912
|
+
} catch (error) {
|
|
14913
|
+
if (error.type) throw error;
|
|
14914
|
+
throw createNetworkError.network(error.message);
|
|
14857
14915
|
}
|
|
14858
|
-
|
|
14859
|
-
|
|
14860
|
-
|
|
14861
|
-
|
|
14862
|
-
|
|
14863
|
-
|
|
14864
|
-
|
|
14865
|
-
|
|
14916
|
+
}
|
|
14917
|
+
async function saveUpdates(appId, branchName, payload, anvilUrl = anvil_api_getDefaultAnvilUrl(), authToken) {
|
|
14918
|
+
try {
|
|
14919
|
+
const resp = await fetch(`${anvilUrl}/ide/api/_/apps/${appId}/update?make_fresh_version=false&branch=${branchName}`, {
|
|
14920
|
+
method: "PUT",
|
|
14921
|
+
headers: {
|
|
14922
|
+
Authorization: `Bearer ${authToken}`,
|
|
14923
|
+
"Content-Type": "application/json"
|
|
14924
|
+
},
|
|
14925
|
+
body: JSON.stringify(payload)
|
|
14926
|
+
});
|
|
14927
|
+
const data = await resp.json();
|
|
14928
|
+
if (401 === resp.status) throw createAuthError.invalid(`Authentication failed (401): ${data.error || "unauthorized"}`);
|
|
14929
|
+
if (403 === resp.status) throw createAuthError.invalid(`Authentication failed (403): ${data.error || "unauthorized"}\n This may indicate:\n - The OAuth token doesn't have permission to write to app ${appId}\n - The app belongs to a different user or organization\n - The OAuth token is missing required scopes (apps:write)`);
|
|
14930
|
+
return {
|
|
14931
|
+
version: data.version,
|
|
14932
|
+
overtaken: data.overtaken,
|
|
14933
|
+
latest_version: data.latest_version,
|
|
14934
|
+
error: 200 !== resp.status ? data.error || `Status ${resp.status}` : void 0
|
|
14935
|
+
};
|
|
14936
|
+
} catch (error) {
|
|
14937
|
+
if (error.type) throw error;
|
|
14938
|
+
throw createNetworkError.network(error.message);
|
|
14866
14939
|
}
|
|
14867
|
-
|
|
14868
|
-
|
|
14869
|
-
|
|
14870
|
-
|
|
14871
|
-
|
|
14940
|
+
}
|
|
14941
|
+
function anvil_api_getGitFetchUrl(appId, authToken, gitUrl = anvil_api_getDefaultAnvilUrl()) {
|
|
14942
|
+
const url = new URL(gitUrl);
|
|
14943
|
+
const encodedToken = encodeURIComponent(authToken);
|
|
14944
|
+
return `${url.protocol}//git:${encodedToken}@${url.hostname}${url.port ? ":" + url.port : ""}/git/${appId}.git?no_freeze=true&q=`;
|
|
14945
|
+
}
|
|
14946
|
+
function anvil_api_getGitPushUrl(appId, authToken, anvilUrl = anvil_api_getDefaultAnvilUrl()) {
|
|
14947
|
+
const url = new URL(anvilUrl);
|
|
14948
|
+
const encodedToken = encodeURIComponent(authToken);
|
|
14949
|
+
return `${url.protocol}//git:${encodedToken}@${url.hostname}${url.port ? ":" + url.port : ""}/git/${appId}.git`;
|
|
14950
|
+
}
|
|
14951
|
+
function getWebSocketUrl(appId, authToken, anvilUrl = anvil_api_getDefaultAnvilUrl()) {
|
|
14952
|
+
return anvilUrl.replace(/^http/, "ws") + `/ide/api/_/apps/${appId}/ws?access_token=${authToken}`;
|
|
14953
|
+
}
|
|
14954
|
+
async function getLatestVersion() {
|
|
14955
|
+
try {
|
|
14956
|
+
const response = await fetch("https://registry.npmjs.org/@anvil-works/anvil-cli/latest");
|
|
14957
|
+
if (!response.ok) return null;
|
|
14958
|
+
const data = await response.json();
|
|
14959
|
+
return data.version;
|
|
14960
|
+
} catch (e) {
|
|
14961
|
+
return null;
|
|
14872
14962
|
}
|
|
14873
|
-
|
|
14874
|
-
|
|
14875
|
-
|
|
14963
|
+
}
|
|
14964
|
+
function anvil_api_filterCandidates(candidates, explicitUrl, explicitUsername) {
|
|
14965
|
+
let filtered = candidates;
|
|
14966
|
+
if (explicitUrl) {
|
|
14967
|
+
const normalizedExplicit = config_normalizeAnvilUrl(explicitUrl);
|
|
14968
|
+
filtered = filtered.filter((c)=>c.detectedUrl && config_normalizeAnvilUrl(c.detectedUrl) === normalizedExplicit);
|
|
14876
14969
|
}
|
|
14877
|
-
|
|
14878
|
-
|
|
14879
|
-
|
|
14880
|
-
|
|
14881
|
-
|
|
14882
|
-
|
|
14883
|
-
|
|
14884
|
-
|
|
14885
|
-
|
|
14886
|
-
|
|
14887
|
-
|
|
14888
|
-
|
|
14889
|
-
|
|
14890
|
-
|
|
14891
|
-
|
|
14892
|
-
|
|
14893
|
-
|
|
14894
|
-
|
|
14970
|
+
if (explicitUsername) filtered = filtered.filter((c)=>!c.detectedUsername || c.detectedUsername === explicitUsername);
|
|
14971
|
+
return filtered;
|
|
14972
|
+
}
|
|
14973
|
+
function anvil_api_formatCandidateLabel(candidate) {
|
|
14974
|
+
const parts = [
|
|
14975
|
+
candidate.appId
|
|
14976
|
+
];
|
|
14977
|
+
if (candidate.detectedUrl) if (candidate.detectedUsername) parts.push(`(${candidate.detectedUsername} on ${candidate.detectedUrl})`);
|
|
14978
|
+
else parts.push(`(${candidate.detectedUrl})`);
|
|
14979
|
+
parts.push(`- ${candidate.description}`);
|
|
14980
|
+
return parts.join(" ");
|
|
14981
|
+
}
|
|
14982
|
+
function anvil_api_lookupRemoteInfoForAppId(appId, detectedRemotes) {
|
|
14983
|
+
const matches = detectedRemotes.filter((c)=>c.appId === appId);
|
|
14984
|
+
if (0 === matches.length) return {};
|
|
14985
|
+
const withUsername = matches.find((c)=>c.detectedUsername);
|
|
14986
|
+
if (withUsername) return {
|
|
14987
|
+
detectedUrl: withUsername.detectedUrl,
|
|
14988
|
+
detectedUsername: withUsername.detectedUsername
|
|
14989
|
+
};
|
|
14990
|
+
return {
|
|
14991
|
+
detectedUrl: matches[0].detectedUrl,
|
|
14992
|
+
detectedUsername: matches[0].detectedUsername
|
|
14993
|
+
};
|
|
14994
|
+
}
|
|
14995
|
+
async function anvil_api_detectAppIdsFromAllRemotes(repoPath) {
|
|
14996
|
+
const git = esm_default(repoPath);
|
|
14997
|
+
const out = [];
|
|
14998
|
+
try {
|
|
14999
|
+
const remotes = await git.getRemotes(true);
|
|
15000
|
+
for (const remote of remotes){
|
|
15001
|
+
const httpMatch = remote.refs.fetch?.match(/(https?):\/\/(?:[^@\/]+@)?([^\/]+)\/git\/([A-Z0-9]+)\.git/);
|
|
15002
|
+
if (httpMatch) {
|
|
15003
|
+
const [, scheme, host, detectedAppId] = httpMatch;
|
|
15004
|
+
const origin = new URL(`${scheme}://${host}`).origin;
|
|
15005
|
+
out.push({
|
|
15006
|
+
appId: detectedAppId,
|
|
15007
|
+
source: "remote",
|
|
15008
|
+
description: `Git remote '${remote.name}'`,
|
|
15009
|
+
detectedUrl: config_normalizeAnvilUrl(origin)
|
|
15010
|
+
});
|
|
15011
|
+
continue;
|
|
15012
|
+
}
|
|
15013
|
+
const sshMatch = remote.refs.fetch?.match(/ssh:\/\/([^@]+)@([^:]+):(\d+)\/(?:git\/)?([A-Z0-9]+)\.git/);
|
|
15014
|
+
if (sshMatch) {
|
|
15015
|
+
const [, usernamePart, host, , detectedAppId] = sshMatch;
|
|
15016
|
+
const detectedUsername = usernamePart.includes("%") ? decodeURIComponent(usernamePart) : usernamePart;
|
|
15017
|
+
const finalUsername = "git" !== detectedUsername ? detectedUsername : void 0;
|
|
15018
|
+
out.push({
|
|
15019
|
+
appId: detectedAppId,
|
|
15020
|
+
source: "remote",
|
|
15021
|
+
description: `Git remote '${remote.name}' (SSH)`,
|
|
15022
|
+
detectedUrl: config_normalizeAnvilUrl(host),
|
|
15023
|
+
detectedUsername: finalUsername
|
|
14895
15024
|
});
|
|
14896
|
-
throw errors_createGitError.fetchFailed(err.message);
|
|
14897
15025
|
}
|
|
14898
|
-
attempt++;
|
|
14899
|
-
this.emit("fetch-retry", {
|
|
14900
|
-
attempt,
|
|
14901
|
-
delayMs: FETCH_RETRY_DELAY_MS,
|
|
14902
|
-
error: err.message
|
|
14903
|
-
});
|
|
14904
|
-
logger_logger.verbose(`git fetch race (attempt ${attempt}, sleeping ${FETCH_RETRY_DELAY_MS}ms): ${err.message}`);
|
|
14905
|
-
await (0, external_timers_promises_namespaceObject.setTimeout)(FETCH_RETRY_DELAY_MS);
|
|
14906
|
-
}
|
|
14907
|
-
}
|
|
14908
|
-
async reset(ref, mode = "mixed") {
|
|
14909
|
-
await this.runGitCommandWithIndexLockRetry("reset", ()=>this.git.reset([
|
|
14910
|
-
`--${mode}`,
|
|
14911
|
-
ref
|
|
14912
|
-
]));
|
|
14913
|
-
}
|
|
14914
|
-
async checkout(paths) {
|
|
14915
|
-
await this.runGitCommandWithIndexLockRetry("checkout", ()=>this.git.checkout(paths));
|
|
14916
|
-
}
|
|
14917
|
-
async runGitCommandWithIndexLockRetry(command, operation) {
|
|
14918
|
-
let lastError;
|
|
14919
|
-
for(let attempt = 0; attempt <= git_GitService.INDEX_LOCK_RETRY_DELAYS_MS.length; attempt += 1)try {
|
|
14920
|
-
await operation();
|
|
14921
|
-
return;
|
|
14922
|
-
} catch (e) {
|
|
14923
|
-
lastError = e;
|
|
14924
|
-
if (!this.isIndexLockError(e) || attempt === git_GitService.INDEX_LOCK_RETRY_DELAYS_MS.length) throw errors_createGitError.commandFailed(command, e.message);
|
|
14925
|
-
await (0, external_timers_promises_namespaceObject.setTimeout)(git_GitService.INDEX_LOCK_RETRY_DELAYS_MS[attempt]);
|
|
14926
15026
|
}
|
|
14927
|
-
|
|
14928
|
-
|
|
14929
|
-
|
|
14930
|
-
|
|
14931
|
-
|
|
14932
|
-
|
|
14933
|
-
|
|
14934
|
-
|
|
14935
|
-
|
|
14936
|
-
|
|
14937
|
-
|
|
14938
|
-
|
|
14939
|
-
|
|
14940
|
-
|
|
14941
|
-
|
|
14942
|
-
|
|
14943
|
-
|
|
14944
|
-
|
|
15027
|
+
} catch (_e) {}
|
|
15028
|
+
return out;
|
|
15029
|
+
}
|
|
15030
|
+
async function anvil_api_detectAppIdsByCommitLookup(repoPath, options) {
|
|
15031
|
+
const anvilUrl = options.anvilUrl || resolveAnvilUrl();
|
|
15032
|
+
const username = options.username;
|
|
15033
|
+
const git = esm_default(repoPath);
|
|
15034
|
+
const out = [];
|
|
15035
|
+
try {
|
|
15036
|
+
const authToken = await auth_getValidAuthToken(anvilUrl, username);
|
|
15037
|
+
const commitId = (await git.revparse([
|
|
15038
|
+
"HEAD"
|
|
15039
|
+
]))?.trim();
|
|
15040
|
+
if (!commitId) return out;
|
|
15041
|
+
const branchName = await git_getCurrentOrFallbackBranchName(git);
|
|
15042
|
+
const resp = await fetch(`${anvilUrl}/ide/api/_/apps/lookup-by-commit`, {
|
|
15043
|
+
method: "POST",
|
|
15044
|
+
headers: {
|
|
15045
|
+
Authorization: `Bearer ${authToken}`,
|
|
15046
|
+
"Content-Type": "application/json"
|
|
15047
|
+
},
|
|
15048
|
+
body: JSON.stringify({
|
|
15049
|
+
commit_id: commitId,
|
|
15050
|
+
branch_name: branchName
|
|
15051
|
+
})
|
|
15052
|
+
});
|
|
15053
|
+
logger_logger.debug(`Reverse lookup by commit ${commitId} on branch ${branchName} returned ${resp.status}`);
|
|
15054
|
+
if (!resp.ok) {
|
|
15055
|
+
const errorBody = await resp.text();
|
|
15056
|
+
logger_logger.debug(`lookup-by-commit error: ${errorBody}`);
|
|
14945
15057
|
}
|
|
14946
|
-
|
|
14947
|
-
|
|
14948
|
-
|
|
14949
|
-
|
|
14950
|
-
|
|
14951
|
-
|
|
14952
|
-
|
|
14953
|
-
|
|
14954
|
-
|
|
15058
|
+
if (resp.ok) {
|
|
15059
|
+
const data = await resp.json();
|
|
15060
|
+
logger_logger.debug(`data ${JSON.stringify(data)}`);
|
|
15061
|
+
const apps = data?.apps ?? [];
|
|
15062
|
+
for (const app of apps)if (app?.app_id) out.push({
|
|
15063
|
+
appId: app.app_id,
|
|
15064
|
+
source: "remote",
|
|
15065
|
+
description: `Reverse lookup by commit${app.branch ? ` on branch '${app.branch}'` : ""}`
|
|
15066
|
+
});
|
|
14955
15067
|
}
|
|
15068
|
+
} catch (_e) {}
|
|
15069
|
+
return out;
|
|
15070
|
+
}
|
|
15071
|
+
const external_fs_promises_namespaceObject = require("fs/promises");
|
|
15072
|
+
var external_fs_promises_default = /*#__PURE__*/ __webpack_require__.n(external_fs_promises_namespaceObject);
|
|
15073
|
+
function normalizeLineEndings(content) {
|
|
15074
|
+
return content.replace(/\r\n/g, "\n");
|
|
15075
|
+
}
|
|
15076
|
+
function pythonifyName(name) {
|
|
15077
|
+
return name.replace(/[^A-z0-9]/g, "_").replace(/^[0-9]/, "_$&");
|
|
15078
|
+
}
|
|
15079
|
+
function extractPythonName(relativePath, skipParts = 1) {
|
|
15080
|
+
const parts = relativePath.slice(0, -3).split("/");
|
|
15081
|
+
const isPackage = relativePath.endsWith("__init__.py");
|
|
15082
|
+
const relevantParts = isPackage ? parts.slice(skipParts, -1) : parts.slice(skipParts);
|
|
15083
|
+
return relevantParts.map(pythonifyName).join(".");
|
|
15084
|
+
}
|
|
15085
|
+
function deepEqual(a, b) {
|
|
15086
|
+
if (a === b) return true;
|
|
15087
|
+
if (null == a || null == b) return false;
|
|
15088
|
+
if (typeof a !== typeof b) return false;
|
|
15089
|
+
if ("object" != typeof a) return a === b;
|
|
15090
|
+
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
|
15091
|
+
if (Array.isArray(a)) {
|
|
15092
|
+
if (a.length !== b.length) return false;
|
|
15093
|
+
return a.every((item, index)=>deepEqual(item, b[index]));
|
|
14956
15094
|
}
|
|
14957
|
-
|
|
14958
|
-
|
|
14959
|
-
|
|
14960
|
-
|
|
14961
|
-
|
|
14962
|
-
|
|
15095
|
+
const keysA = Object.keys(a);
|
|
15096
|
+
const keysB = Object.keys(b);
|
|
15097
|
+
if (keysA.length !== keysB.length) return false;
|
|
15098
|
+
return keysA.every((key)=>deepEqual(a[key], b[key]));
|
|
15099
|
+
}
|
|
15100
|
+
function parseHtmlWithFrontmatter(htmlContent) {
|
|
15101
|
+
const frontmatterPattern = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
|
|
15102
|
+
const match = htmlContent.match(frontmatterPattern);
|
|
15103
|
+
if (match) {
|
|
15104
|
+
const yamlStr = match[1];
|
|
15105
|
+
const html = match[2];
|
|
15106
|
+
const frontmatter = yamlStr ? external_js_yaml_default().load(yamlStr) ?? {} : {};
|
|
15107
|
+
return {
|
|
15108
|
+
frontmatter,
|
|
15109
|
+
html
|
|
15110
|
+
};
|
|
14963
15111
|
}
|
|
14964
|
-
|
|
14965
|
-
|
|
14966
|
-
|
|
14967
|
-
|
|
14968
|
-
|
|
14969
|
-
|
|
14970
|
-
|
|
14971
|
-
|
|
14972
|
-
|
|
14973
|
-
|
|
14974
|
-
|
|
14975
|
-
|
|
15112
|
+
return {
|
|
15113
|
+
frontmatter: {},
|
|
15114
|
+
html: htmlContent
|
|
15115
|
+
};
|
|
15116
|
+
}
|
|
15117
|
+
function http_formatHttpError(prefix, status, body) {
|
|
15118
|
+
if (!body) return `${prefix}: ${status}`;
|
|
15119
|
+
try {
|
|
15120
|
+
const parsed = JSON.parse(body);
|
|
15121
|
+
if ("string" == typeof parsed.error && parsed.error.trim()) return `${prefix}: ${parsed.error} (${status})`;
|
|
15122
|
+
} catch {}
|
|
15123
|
+
return `${prefix}: ${status} ${body}`;
|
|
15124
|
+
}
|
|
15125
|
+
const ANVIL_GITIGNORE_ENTRY = "/.anvil/";
|
|
15126
|
+
async function ensureProjectGitignoreIgnoresAnvilDir(projectRoot) {
|
|
15127
|
+
const rootGitignorePath = external_path_default().join(projectRoot, ".gitignore");
|
|
15128
|
+
try {
|
|
15129
|
+
const existing = await external_fs_.promises.readFile(rootGitignorePath, "utf8");
|
|
15130
|
+
if (existing.includes(ANVIL_GITIGNORE_ENTRY)) return false;
|
|
15131
|
+
const prefix = existing.endsWith("\n") || 0 === existing.length ? "" : "\n";
|
|
15132
|
+
await external_fs_.promises.writeFile(rootGitignorePath, `${existing}${prefix}${ANVIL_GITIGNORE_ENTRY}\n`, "utf8");
|
|
15133
|
+
return true;
|
|
15134
|
+
} catch (error) {
|
|
15135
|
+
if ("ENOENT" !== error.code) throw error;
|
|
15136
|
+
await external_fs_.promises.writeFile(rootGitignorePath, `${ANVIL_GITIGNORE_ENTRY}\n`, "utf8");
|
|
15137
|
+
return true;
|
|
14976
15138
|
}
|
|
14977
|
-
|
|
14978
|
-
|
|
14979
|
-
|
|
14980
|
-
|
|
14981
|
-
|
|
14982
|
-
|
|
14983
|
-
|
|
14984
|
-
|
|
14985
|
-
|
|
14986
|
-
|
|
14987
|
-
|
|
14988
|
-
|
|
14989
|
-
|
|
14990
|
-
|
|
14991
|
-
|
|
14992
|
-
|
|
15139
|
+
}
|
|
15140
|
+
const ANVIL_DEPS_DIR = ".anvil/deps";
|
|
15141
|
+
const ANVIL_DEPS_MANIFEST = "manifest.json";
|
|
15142
|
+
const DEPS_MANIFEST_VERSION = 3;
|
|
15143
|
+
async function fetchAllDependencies(appId, anvilUrl, options = {}) {
|
|
15144
|
+
const { commit, includeDocs = true, knownDependencies = [] } = options;
|
|
15145
|
+
anvilUrl ??= await auth_resolveAuthAnvilUrl();
|
|
15146
|
+
const token = await auth_getValidAuthToken(anvilUrl, options.username);
|
|
15147
|
+
const body = {
|
|
15148
|
+
include_docs: includeDocs,
|
|
15149
|
+
known_dependencies: knownDependencies
|
|
15150
|
+
};
|
|
15151
|
+
if (commit) body.commit = commit;
|
|
15152
|
+
const resp = await fetch(`${anvilUrl}/ide/api/_/apps/${appId}/resolved-dependencies`, {
|
|
15153
|
+
method: "POST",
|
|
15154
|
+
headers: {
|
|
15155
|
+
Authorization: `Bearer ${token}`,
|
|
15156
|
+
"Content-Type": "application/json"
|
|
15157
|
+
},
|
|
15158
|
+
body: JSON.stringify(body)
|
|
15159
|
+
});
|
|
15160
|
+
if (!resp.ok) {
|
|
15161
|
+
const errorBody = await resp.text();
|
|
15162
|
+
throw new Error(http_formatHttpError("Failed to fetch dependencies", resp.status, errorBody));
|
|
14993
15163
|
}
|
|
14994
|
-
|
|
14995
|
-
|
|
14996
|
-
|
|
14997
|
-
|
|
14998
|
-
|
|
14999
|
-
|
|
15000
|
-
|
|
15001
|
-
|
|
15002
|
-
|
|
15164
|
+
return await resp.json();
|
|
15165
|
+
}
|
|
15166
|
+
async function refreshDependencyCache(projectRoot, appId, anvilUrl, options = {}) {
|
|
15167
|
+
auth_setRepoContext(projectRoot);
|
|
15168
|
+
anvilUrl ??= await auth_resolveAuthAnvilUrl();
|
|
15169
|
+
const includeDocs = options.includeDocs ?? true;
|
|
15170
|
+
const git = new git_GitService(projectRoot);
|
|
15171
|
+
const commit = options.commit ?? await git.getCommitId();
|
|
15172
|
+
const sourceYaml = await git.show(`${commit}:anvil.yaml`).catch((error)=>{
|
|
15173
|
+
if (options.commit) return null;
|
|
15174
|
+
throw error;
|
|
15175
|
+
});
|
|
15176
|
+
const sourceDependencies = null === sourceYaml ? null : normalizeAnvilYamlDependenciesFromContent(sourceYaml);
|
|
15177
|
+
const knownDependencies = await getKnownDependenciesForCache(projectRoot, includeDocs);
|
|
15178
|
+
const response = await fetchAllDependencies(appId, anvilUrl, {
|
|
15179
|
+
username: options.username,
|
|
15180
|
+
commit,
|
|
15181
|
+
includeDocs,
|
|
15182
|
+
knownDependencies
|
|
15183
|
+
});
|
|
15184
|
+
if (!response.resolved_dependencies.length) {
|
|
15185
|
+
await clearDepsCache(projectRoot);
|
|
15186
|
+
return {
|
|
15187
|
+
response,
|
|
15188
|
+
addedGitignoreEntry: false
|
|
15189
|
+
};
|
|
15003
15190
|
}
|
|
15004
|
-
|
|
15005
|
-
|
|
15006
|
-
|
|
15007
|
-
|
|
15008
|
-
|
|
15009
|
-
|
|
15010
|
-
|
|
15011
|
-
|
|
15012
|
-
|
|
15013
|
-
|
|
15014
|
-
|
|
15015
|
-
|
|
15016
|
-
|
|
15017
|
-
|
|
15018
|
-
|
|
15019
|
-
|
|
15191
|
+
const addedGitignoreEntry = await ensureProjectGitignoreIgnoresAnvilDir(projectRoot);
|
|
15192
|
+
await writeAllDepsToCache(projectRoot, response, {
|
|
15193
|
+
includeDocs,
|
|
15194
|
+
sourceDependencies
|
|
15195
|
+
});
|
|
15196
|
+
return {
|
|
15197
|
+
response,
|
|
15198
|
+
addedGitignoreEntry
|
|
15199
|
+
};
|
|
15200
|
+
}
|
|
15201
|
+
function depsDir(projectRoot) {
|
|
15202
|
+
return external_path_default().join(projectRoot, ANVIL_DEPS_DIR);
|
|
15203
|
+
}
|
|
15204
|
+
function depsManifestPath(projectRoot) {
|
|
15205
|
+
return external_path_default().join(depsDir(projectRoot), ANVIL_DEPS_MANIFEST);
|
|
15206
|
+
}
|
|
15207
|
+
function isResolvedDependencyManifestEntry(value) {
|
|
15208
|
+
if (!value || "object" != typeof value) return false;
|
|
15209
|
+
const entry = value;
|
|
15210
|
+
return "string" == typeof entry.app_id && entry.app_id.length > 0 && "string" == typeof entry.commit_id && entry.commit_id.length > 0 && (void 0 === entry.branch || "string" == typeof entry.branch);
|
|
15211
|
+
}
|
|
15212
|
+
function isCachedDependencyManifestEntry(value) {
|
|
15213
|
+
if (!isResolvedDependencyManifestEntry(value)) return false;
|
|
15214
|
+
const entry = value;
|
|
15215
|
+
return "string" == typeof entry.package_name && entry.package_name.length > 0;
|
|
15216
|
+
}
|
|
15217
|
+
function isDepsCacheManifest(value) {
|
|
15218
|
+
if (!value || "object" != typeof value) return false;
|
|
15219
|
+
const manifest = value;
|
|
15220
|
+
return manifest.version === DEPS_MANIFEST_VERSION && "boolean" == typeof manifest.includeDocs && (null === manifest.source_dependencies || Array.isArray(manifest.source_dependencies)) && Array.isArray(manifest.resolved_dependencies) && manifest.resolved_dependencies.every(isResolvedDependencyManifestEntry) && Array.isArray(manifest.cached_dependencies) && manifest.cached_dependencies.every(isCachedDependencyManifestEntry);
|
|
15221
|
+
}
|
|
15222
|
+
async function readDepsCacheManifest(projectRoot) {
|
|
15223
|
+
try {
|
|
15224
|
+
const raw = await external_fs_promises_default().readFile(depsManifestPath(projectRoot), "utf-8");
|
|
15225
|
+
const parsed = JSON.parse(raw);
|
|
15226
|
+
return isDepsCacheManifest(parsed) ? parsed : void 0;
|
|
15227
|
+
} catch {
|
|
15228
|
+
return;
|
|
15020
15229
|
}
|
|
15021
|
-
|
|
15022
|
-
|
|
15023
|
-
|
|
15024
|
-
|
|
15025
|
-
|
|
15026
|
-
|
|
15027
|
-
|
|
15028
|
-
|
|
15029
|
-
|
|
15230
|
+
}
|
|
15231
|
+
async function getKnownDependenciesForCache(projectRoot, includeDocs) {
|
|
15232
|
+
const manifest = await readDepsCacheManifest(projectRoot);
|
|
15233
|
+
if (!manifest || manifest.includeDocs !== includeDocs) return [];
|
|
15234
|
+
return manifest.resolved_dependencies.map(({ app_id, commit_id })=>({
|
|
15235
|
+
app_id,
|
|
15236
|
+
commit_id
|
|
15237
|
+
}));
|
|
15238
|
+
}
|
|
15239
|
+
function getDependencyWatchSubscriptionsFromManifest(manifest) {
|
|
15240
|
+
if (!manifest) return [];
|
|
15241
|
+
const cachedByAppId = new Map(manifest.cached_dependencies.map((dep)=>[
|
|
15242
|
+
dep.app_id,
|
|
15243
|
+
dep
|
|
15244
|
+
]));
|
|
15245
|
+
return manifest.resolved_dependencies.flatMap((dep)=>{
|
|
15246
|
+
if (!dep.branch) return [];
|
|
15247
|
+
return [
|
|
15248
|
+
{
|
|
15249
|
+
appId: dep.app_id,
|
|
15250
|
+
branch: dep.branch,
|
|
15251
|
+
packageName: cachedByAppId.get(dep.app_id)?.package_name
|
|
15252
|
+
}
|
|
15253
|
+
];
|
|
15254
|
+
});
|
|
15255
|
+
}
|
|
15256
|
+
function normalizeAnvilYamlDependenciesFromContent(content) {
|
|
15257
|
+
const parsed = external_js_yaml_default().load(content);
|
|
15258
|
+
if (!parsed || "object" != typeof parsed || !Array.isArray(parsed.dependencies)) return [];
|
|
15259
|
+
return normalizeAnvilYamlDependenciesValue(parsed.dependencies);
|
|
15260
|
+
}
|
|
15261
|
+
function normalizeAnvilYamlDependenciesValue(value) {
|
|
15262
|
+
if (!Array.isArray(value)) return [];
|
|
15263
|
+
return value.map(normalizeForComparison);
|
|
15264
|
+
}
|
|
15265
|
+
async function readAnvilYamlDependencies(projectRoot) {
|
|
15266
|
+
try {
|
|
15267
|
+
const content = await external_fs_promises_default().readFile(external_path_default().join(projectRoot, "anvil.yaml"), "utf-8");
|
|
15268
|
+
return normalizeAnvilYamlDependenciesFromContent(content);
|
|
15269
|
+
} catch {
|
|
15270
|
+
return [];
|
|
15030
15271
|
}
|
|
15031
|
-
|
|
15032
|
-
|
|
15033
|
-
|
|
15034
|
-
|
|
15035
|
-
|
|
15036
|
-
|
|
15037
|
-
|
|
15038
|
-
|
|
15272
|
+
}
|
|
15273
|
+
function anvilYamlDependenciesEqual(left, right) {
|
|
15274
|
+
return deepEqual(left, right);
|
|
15275
|
+
}
|
|
15276
|
+
function normalizeForComparison(value) {
|
|
15277
|
+
if (Array.isArray(value)) return value.map(normalizeForComparison);
|
|
15278
|
+
if (value && "object" == typeof value) return Object.fromEntries(Object.entries(value).sort(([left], [right])=>left.localeCompare(right)).map(([key, entryValue])=>[
|
|
15279
|
+
key,
|
|
15280
|
+
normalizeForComparison(entryValue)
|
|
15281
|
+
]));
|
|
15282
|
+
return value;
|
|
15283
|
+
}
|
|
15284
|
+
function cachedManifestEntry(dep, packageName) {
|
|
15285
|
+
return {
|
|
15286
|
+
app_id: dep.app_id,
|
|
15287
|
+
commit_id: dep.commit_id,
|
|
15288
|
+
...dep.branch ? {
|
|
15289
|
+
branch: dep.branch
|
|
15290
|
+
} : {},
|
|
15291
|
+
package_name: packageName
|
|
15292
|
+
};
|
|
15293
|
+
}
|
|
15294
|
+
function safeDependencyPath(filePath, kind) {
|
|
15295
|
+
const normalizedPath = external_path_default().normalize(filePath);
|
|
15296
|
+
if (external_path_default().isAbsolute(normalizedPath) || normalizedPath.startsWith("..")) throw new Error(`Invalid dependency ${kind} path: ${filePath}`);
|
|
15297
|
+
return normalizedPath;
|
|
15298
|
+
}
|
|
15299
|
+
function dependencyPythonPath(name, kind) {
|
|
15300
|
+
const parts = name.split(".");
|
|
15301
|
+
if (0 === parts.length || parts.some((part)=>!part || "." === part || ".." === part || part.includes("/") || part.includes("\\"))) throw new Error(`Invalid dependency ${kind} name: ${name}`);
|
|
15302
|
+
return external_path_default().join(...parts);
|
|
15303
|
+
}
|
|
15304
|
+
async function writeDepToCache(projectRoot, dep) {
|
|
15305
|
+
const depDir = external_path_default().join(projectRoot, ANVIL_DEPS_DIR, dep.package_name);
|
|
15306
|
+
await external_fs_promises_default().rm(depDir, {
|
|
15307
|
+
recursive: true,
|
|
15308
|
+
force: true
|
|
15309
|
+
});
|
|
15310
|
+
await external_fs_promises_default().mkdir(external_path_default().join(depDir, "client_code"), {
|
|
15311
|
+
recursive: true
|
|
15312
|
+
});
|
|
15313
|
+
await external_fs_promises_default().mkdir(external_path_default().join(depDir, "server_code"), {
|
|
15314
|
+
recursive: true
|
|
15315
|
+
});
|
|
15316
|
+
await external_fs_promises_default().writeFile(external_path_default().join(depDir, "anvil.yaml"), external_js_yaml_default().dump({
|
|
15317
|
+
package_name: dep.package_name
|
|
15318
|
+
}));
|
|
15319
|
+
for (const mod of dep.modules ?? []){
|
|
15320
|
+
const modulePath = external_path_default().join(depDir, "client_code", dependencyPythonPath(mod.name, "module"));
|
|
15321
|
+
if (mod.is_package) {
|
|
15322
|
+
await external_fs_promises_default().mkdir(modulePath, {
|
|
15323
|
+
recursive: true
|
|
15324
|
+
});
|
|
15325
|
+
await external_fs_promises_default().writeFile(external_path_default().join(modulePath, "__init__.py"), mod.code);
|
|
15326
|
+
} else {
|
|
15327
|
+
const moduleFile = `${modulePath}.py`;
|
|
15328
|
+
await external_fs_promises_default().mkdir(external_path_default().dirname(moduleFile), {
|
|
15329
|
+
recursive: true
|
|
15330
|
+
});
|
|
15331
|
+
await external_fs_promises_default().writeFile(moduleFile, mod.code);
|
|
15039
15332
|
}
|
|
15040
15333
|
}
|
|
15041
|
-
|
|
15042
|
-
|
|
15043
|
-
|
|
15044
|
-
|
|
15045
|
-
|
|
15046
|
-
|
|
15047
|
-
|
|
15048
|
-
|
|
15049
|
-
|
|
15050
|
-
|
|
15051
|
-
|
|
15052
|
-
|
|
15053
|
-
|
|
15334
|
+
for (const form of dep.forms ?? []){
|
|
15335
|
+
const { code, class_name, is_package, ...formTemplate } = form;
|
|
15336
|
+
const formPath = external_path_default().join(depDir, "client_code", dependencyPythonPath(class_name, "form"));
|
|
15337
|
+
if (is_package) {
|
|
15338
|
+
await external_fs_promises_default().mkdir(formPath, {
|
|
15339
|
+
recursive: true
|
|
15340
|
+
});
|
|
15341
|
+
await external_fs_promises_default().writeFile(external_path_default().join(formPath, "__init__.py"), code);
|
|
15342
|
+
await external_fs_promises_default().writeFile(external_path_default().join(formPath, "form_template.yaml"), external_js_yaml_default().dump(formTemplate));
|
|
15343
|
+
} else {
|
|
15344
|
+
const formCodeFile = `${formPath}.py`;
|
|
15345
|
+
await external_fs_promises_default().mkdir(external_path_default().dirname(formCodeFile), {
|
|
15346
|
+
recursive: true
|
|
15347
|
+
});
|
|
15348
|
+
await external_fs_promises_default().writeFile(formCodeFile, code);
|
|
15349
|
+
await external_fs_promises_default().writeFile(`${formPath}.yaml`, external_js_yaml_default().dump(formTemplate));
|
|
15054
15350
|
}
|
|
15055
15351
|
}
|
|
15056
|
-
|
|
15057
|
-
|
|
15058
|
-
|
|
15059
|
-
|
|
15060
|
-
|
|
15061
|
-
|
|
15062
|
-
|
|
15063
|
-
|
|
15064
|
-
|
|
15065
|
-
await
|
|
15066
|
-
|
|
15067
|
-
|
|
15068
|
-
|
|
15069
|
-
]);
|
|
15070
|
-
} catch (e) {}
|
|
15071
|
-
}
|
|
15072
|
-
async getRemotes() {
|
|
15073
|
-
try {
|
|
15074
|
-
const remotes = await this.git.getRemotes(true);
|
|
15075
|
-
return remotes.map((r)=>({
|
|
15076
|
-
name: r.name,
|
|
15077
|
-
fetchUrl: r.refs.fetch
|
|
15078
|
-
}));
|
|
15079
|
-
} catch (e) {
|
|
15080
|
-
throw errors_createGitError.commandFailed("remote", e.message);
|
|
15352
|
+
for (const mod of dep.server_modules ?? []){
|
|
15353
|
+
const modulePath = external_path_default().join(depDir, "server_code", dependencyPythonPath(mod.name, "server module"));
|
|
15354
|
+
if (mod.is_package) {
|
|
15355
|
+
await external_fs_promises_default().mkdir(modulePath, {
|
|
15356
|
+
recursive: true
|
|
15357
|
+
});
|
|
15358
|
+
await external_fs_promises_default().writeFile(external_path_default().join(modulePath, "__init__.py"), mod.code);
|
|
15359
|
+
} else {
|
|
15360
|
+
const moduleFile = `${modulePath}.py`;
|
|
15361
|
+
await external_fs_promises_default().mkdir(external_path_default().dirname(moduleFile), {
|
|
15362
|
+
recursive: true
|
|
15363
|
+
});
|
|
15364
|
+
await external_fs_promises_default().writeFile(moduleFile, mod.code);
|
|
15081
15365
|
}
|
|
15082
15366
|
}
|
|
15083
|
-
|
|
15084
|
-
const
|
|
15085
|
-
|
|
15367
|
+
for (const asset of dep.assets ?? []){
|
|
15368
|
+
const targetPath = external_path_default().join(depDir, "theme", "assets", safeDependencyPath(asset.name, "asset"));
|
|
15369
|
+
await external_fs_promises_default().mkdir(external_path_default().dirname(targetPath), {
|
|
15370
|
+
recursive: true
|
|
15371
|
+
});
|
|
15372
|
+
await external_fs_promises_default().writeFile(targetPath, Buffer.from(asset.content, "base64"));
|
|
15086
15373
|
}
|
|
15087
|
-
|
|
15088
|
-
const
|
|
15089
|
-
|
|
15090
|
-
|
|
15091
|
-
|
|
15092
|
-
|
|
15093
|
-
const parentDir = external_path_default().dirname(dir);
|
|
15094
|
-
if (parentDir === dir) break;
|
|
15095
|
-
dir = parentDir;
|
|
15096
|
-
}
|
|
15097
|
-
}
|
|
15098
|
-
const sortedDirs = Array.from(directoriesToCheck).sort((a, b)=>b.split("/").length - a.split("/").length);
|
|
15099
|
-
for (const dir of sortedDirs)try {
|
|
15100
|
-
const dirPath = external_path_default().join(this.repoPath, dir);
|
|
15101
|
-
if (!external_fs_.existsSync(dirPath)) continue;
|
|
15102
|
-
const entries = await external_fs_.promises.readdir(dirPath);
|
|
15103
|
-
if (0 === entries.length) await external_fs_.promises.rmdir(dirPath);
|
|
15104
|
-
} catch (error) {}
|
|
15374
|
+
for (const doc of dep.docs ?? []){
|
|
15375
|
+
const targetPath = external_path_default().join(depDir, safeDependencyPath(doc.path, "doc"));
|
|
15376
|
+
await external_fs_promises_default().mkdir(external_path_default().dirname(targetPath), {
|
|
15377
|
+
recursive: true
|
|
15378
|
+
});
|
|
15379
|
+
await external_fs_promises_default().writeFile(targetPath, doc.content);
|
|
15105
15380
|
}
|
|
15106
15381
|
}
|
|
15107
|
-
async function
|
|
15108
|
-
|
|
15109
|
-
|
|
15110
|
-
|
|
15111
|
-
|
|
15112
|
-
|
|
15113
|
-
|
|
15114
|
-
|
|
15115
|
-
|
|
15116
|
-
|
|
15117
|
-
|
|
15118
|
-
|
|
15119
|
-
|
|
15120
|
-
|
|
15121
|
-
|
|
15122
|
-
|
|
15123
|
-
|
|
15124
|
-
|
|
15125
|
-
|
|
15126
|
-
|
|
15127
|
-
|
|
15128
|
-
|
|
15129
|
-
|
|
15130
|
-
|
|
15131
|
-
|
|
15132
|
-
|
|
15133
|
-
|
|
15134
|
-
|
|
15135
|
-
|
|
15136
|
-
|
|
15137
|
-
|
|
15138
|
-
|
|
15139
|
-
|
|
15140
|
-
|
|
15141
|
-
|
|
15142
|
-
|
|
15143
|
-
|
|
15144
|
-
|
|
15145
|
-
|
|
15146
|
-
|
|
15147
|
-
|
|
15382
|
+
async function writeAllDepsToCache(projectRoot, response, options = {}) {
|
|
15383
|
+
const includeDocs = options.includeDocs ?? true;
|
|
15384
|
+
const manifest = await readDepsCacheManifest(projectRoot);
|
|
15385
|
+
const canReuseExistingCache = manifest?.includeDocs === includeDocs;
|
|
15386
|
+
if (!canReuseExistingCache) await clearDepsCache(projectRoot);
|
|
15387
|
+
const previousCached = canReuseExistingCache ? manifest.cached_dependencies : [];
|
|
15388
|
+
const resolvedAppIds = new Set(response.resolved_dependencies.map((dep)=>dep.app_id));
|
|
15389
|
+
for (const dep of previousCached)if (!resolvedAppIds.has(dep.app_id)) await external_fs_promises_default().rm(external_path_default().join(projectRoot, ANVIL_DEPS_DIR, dep.package_name), {
|
|
15390
|
+
recursive: true,
|
|
15391
|
+
force: true
|
|
15392
|
+
});
|
|
15393
|
+
for (const dep of response.dependencies)await writeDepToCache(projectRoot, dep);
|
|
15394
|
+
const returnedByAppId = new Map(response.dependencies.map((dep)=>[
|
|
15395
|
+
dep.app_id,
|
|
15396
|
+
dep
|
|
15397
|
+
]));
|
|
15398
|
+
const previousByAppId = new Map(previousCached.map((dep)=>[
|
|
15399
|
+
dep.app_id,
|
|
15400
|
+
dep
|
|
15401
|
+
]));
|
|
15402
|
+
const cachedDependencies = response.resolved_dependencies.map((dep)=>{
|
|
15403
|
+
const returned = returnedByAppId.get(dep.app_id);
|
|
15404
|
+
if (returned) return cachedManifestEntry(returned, returned.package_name);
|
|
15405
|
+
const previous = previousByAppId.get(dep.app_id);
|
|
15406
|
+
if (!previous) return;
|
|
15407
|
+
return cachedManifestEntry(dep, previous.package_name);
|
|
15408
|
+
}).filter((dep)=>void 0 !== dep);
|
|
15409
|
+
const newManifest = {
|
|
15410
|
+
version: DEPS_MANIFEST_VERSION,
|
|
15411
|
+
includeDocs,
|
|
15412
|
+
source_dependencies: void 0 === options.sourceDependencies ? await readAnvilYamlDependencies(projectRoot) : options.sourceDependencies,
|
|
15413
|
+
resolved_dependencies: response.resolved_dependencies,
|
|
15414
|
+
cached_dependencies: cachedDependencies
|
|
15415
|
+
};
|
|
15416
|
+
await external_fs_promises_default().mkdir(depsDir(projectRoot), {
|
|
15417
|
+
recursive: true
|
|
15418
|
+
});
|
|
15419
|
+
await external_fs_promises_default().writeFile(depsManifestPath(projectRoot), `${JSON.stringify(newManifest, null, 2)}\n`);
|
|
15420
|
+
}
|
|
15421
|
+
async function clearDepsCache(projectRoot) {
|
|
15422
|
+
await external_fs_promises_default().rm(depsDir(projectRoot), {
|
|
15423
|
+
recursive: true,
|
|
15424
|
+
force: true
|
|
15425
|
+
});
|
|
15148
15426
|
}
|
|
15149
15427
|
const external_chokidar_namespaceObject = require("chokidar");
|
|
15150
15428
|
var external_chokidar_default = /*#__PURE__*/ __webpack_require__.n(external_chokidar_namespaceObject);
|
|
@@ -16208,8 +16486,10 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
16208
16486
|
}
|
|
16209
16487
|
if (void 0 !== value.toolbox_item && !isPlainObject(value.toolbox_item)) formTemplateValidation_pushIssue(issues, path("toolbox_item"), "must be an object");
|
|
16210
16488
|
if (void 0 !== value.layout_metadata && !isPlainObject(value.layout_metadata)) formTemplateValidation_pushIssue(issues, path("layout_metadata"), "must be an object");
|
|
16489
|
+
if (void 0 !== value.help_text && "string" != typeof value.help_text) formTemplateValidation_pushIssue(issues, path("help_text"), "must be a string");
|
|
16211
16490
|
if (void 0 !== value.item_type) if (isPlainObject(value.item_type)) {
|
|
16212
|
-
if (
|
|
16491
|
+
if (void 0 !== value.item_type.table_name) validateNonEmptyString(value.item_type.table_name, path("item_type.table_name"), issues);
|
|
16492
|
+
else if ("number" != typeof value.item_type.table_id) formTemplateValidation_pushIssue(issues, path("item_type.table_id"), "must be a number");
|
|
16213
16493
|
} else formTemplateValidation_pushIssue(issues, path("item_type"), "must be an object");
|
|
16214
16494
|
return issues;
|
|
16215
16495
|
}
|
|
@@ -16282,7 +16562,8 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
16282
16562
|
"toolbox_item",
|
|
16283
16563
|
"layout_metadata",
|
|
16284
16564
|
"item_type",
|
|
16285
|
-
"slots"
|
|
16565
|
+
"slots",
|
|
16566
|
+
"help_text"
|
|
16286
16567
|
]);
|
|
16287
16568
|
const FRONTMATTER_DISALLOWED_KEYS = new Set([
|
|
16288
16569
|
"container",
|
|
@@ -16912,7 +17193,7 @@ print(json.dumps({"issues": issues}))
|
|
|
16912
17193
|
}
|
|
16913
17194
|
function validateScheduledTasks(value, path) {
|
|
16914
17195
|
const issues = [];
|
|
16915
|
-
if (
|
|
17196
|
+
if (null == value) return issues;
|
|
16916
17197
|
if (!Array.isArray(value)) {
|
|
16917
17198
|
validators_pushIssue(issues, path, "must be an array");
|
|
16918
17199
|
return issues;
|
|
@@ -18411,6 +18692,15 @@ print(json.dumps({"issues": issues}))
|
|
|
18411
18692
|
this.hasPendingChanges = true;
|
|
18412
18693
|
await this.processSaveBatchWithEvents();
|
|
18413
18694
|
}
|
|
18695
|
+
async flush() {
|
|
18696
|
+
const requireReady = ()=>{
|
|
18697
|
+
if (this.config.isPaused() || this.config.isCleanedUp() || !this.config.isSettlePeriodOver()) throw new Error("Cannot flush saves while watching is paused, closed, or changing branch");
|
|
18698
|
+
};
|
|
18699
|
+
requireReady();
|
|
18700
|
+
await this.forceSave();
|
|
18701
|
+
requireReady();
|
|
18702
|
+
if (this.hasPendingChanges) throw new Error("Saves remain pending");
|
|
18703
|
+
}
|
|
18414
18704
|
cleanup() {
|
|
18415
18705
|
if (this.hasPendingChanges) {
|
|
18416
18706
|
logger_logger.progressEnd("sync");
|
|
@@ -18507,10 +18797,7 @@ print(json.dumps({"issues": issues}))
|
|
|
18507
18797
|
status = await this.config.gitService.getStatus();
|
|
18508
18798
|
} catch (e) {
|
|
18509
18799
|
logger_logger.error(external_chalk_default().red(`Error reading git status: ${errors_getErrorMessage(e)}`));
|
|
18510
|
-
|
|
18511
|
-
skipped: true,
|
|
18512
|
-
reason: "Git status error"
|
|
18513
|
-
};
|
|
18800
|
+
throw e;
|
|
18514
18801
|
}
|
|
18515
18802
|
let allChanges;
|
|
18516
18803
|
if (this.config.stagedOnly) {
|
|
@@ -19356,6 +19643,7 @@ print(json.dumps({"issues": issues}))
|
|
|
19356
19643
|
try {
|
|
19357
19644
|
const previousSubscriptions = this.wsClient?.getDependencySubscriptions() ?? [];
|
|
19358
19645
|
const { response, addedGitignoreEntry } = await refreshDependencyCache(this.repoPath, this.appId, this.anvilUrl, {
|
|
19646
|
+
username: this.username,
|
|
19359
19647
|
includeDocs: true
|
|
19360
19648
|
});
|
|
19361
19649
|
if (addedGitignoreEntry) logger_logger.info("Added /.anvil/ to .gitignore");
|
|
@@ -19667,6 +19955,12 @@ print(json.dumps({"issues": issues}))
|
|
|
19667
19955
|
if (!this.saveProcessor) return;
|
|
19668
19956
|
return this.saveProcessor.forceSave();
|
|
19669
19957
|
}
|
|
19958
|
+
async flushSaves() {
|
|
19959
|
+
if (!this.saveProcessor || this.isSwitchingForEnvironment) throw new Error("App synchronization is not ready");
|
|
19960
|
+
const branch = this.currentBranch;
|
|
19961
|
+
await this.saveProcessor.flush();
|
|
19962
|
+
if (this.isSwitchingForEnvironment || this.currentBranch !== branch || await this.gitService.getCurrentBranch() !== branch) throw new Error("App branch changed while flushing saves");
|
|
19963
|
+
}
|
|
19670
19964
|
async getSuccessMessage() {
|
|
19671
19965
|
try {
|
|
19672
19966
|
const info = await this.gitService.getCommitInfo();
|
|
@@ -19927,6 +20221,18 @@ print(json.dumps({"issues": issues}))
|
|
|
19927
20221
|
}
|
|
19928
20222
|
throw new Error("Device login expired before it was approved.");
|
|
19929
20223
|
}
|
|
20224
|
+
function quoteForPosixShell(value) {
|
|
20225
|
+
if ("" === value) return "''";
|
|
20226
|
+
return `'${value.replace(/'/g, "'\"'\"'")}'`;
|
|
20227
|
+
}
|
|
20228
|
+
function quoteForCmdShell(value) {
|
|
20229
|
+
const escaped = value.replace(/[%^&|<>()"!]/g, "^$&");
|
|
20230
|
+
return `"${escaped}"`;
|
|
20231
|
+
}
|
|
20232
|
+
function buildShellCommandLine(tokens) {
|
|
20233
|
+
if ("win32" === process.platform) return tokens.map(quoteForCmdShell).join(" ");
|
|
20234
|
+
return tokens.map(quoteForPosixShell).join(" ");
|
|
20235
|
+
}
|
|
19930
20236
|
const CHECKOUT_ERROR_VALUE = "__ERROR__";
|
|
19931
20237
|
function isAbortLikeError(error) {
|
|
19932
20238
|
if (error instanceof Error && "AbortError" === error.name) return true;
|
|
@@ -20105,6 +20411,122 @@ print(json.dumps({"issues": issues}))
|
|
|
20105
20411
|
}
|
|
20106
20412
|
require("inquirer");
|
|
20107
20413
|
require("ora");
|
|
20414
|
+
class CreateCheckoutError extends Error {
|
|
20415
|
+
created;
|
|
20416
|
+
constructor(message, created, options){
|
|
20417
|
+
super(message, options), this.created = created;
|
|
20418
|
+
this.name = "CreateCheckoutError";
|
|
20419
|
+
}
|
|
20420
|
+
}
|
|
20421
|
+
const create_defaultDeps = {
|
|
20422
|
+
getAccountsForUrl: auth_getAccountsForUrl,
|
|
20423
|
+
getValidAuthToken: auth_getValidAuthToken,
|
|
20424
|
+
createApp: createAnvilApp,
|
|
20425
|
+
checkout: executeCheckout
|
|
20426
|
+
};
|
|
20427
|
+
function validateCheckoutOptions(options) {
|
|
20428
|
+
if (false === options.checkout && (void 0 !== options.directory || void 0 !== options.gitUrl || options.open)) throw new Error("--no-checkout cannot be combined with a destination argument, --directory, --git-url, or --open.");
|
|
20429
|
+
}
|
|
20430
|
+
async function validateCreateInput(options) {
|
|
20431
|
+
validateCheckoutOptions(options);
|
|
20432
|
+
const name = options.name.trim();
|
|
20433
|
+
if (!name) throw new Error("App name is required.");
|
|
20434
|
+
const tags = void 0 === options.tags ? void 0 : [
|
|
20435
|
+
...new Set(options.tags.map((tag)=>tag.trim().toLowerCase()))
|
|
20436
|
+
];
|
|
20437
|
+
if (tags && (tags.length > 20 || tags.some((tag)=>tag.length > 50 || !/^[a-z0-9_-]+$/.test(tag)))) throw new Error("Use at most 20 unique tags, each 1–50 characters: letters, numbers, hyphens, or underscores.");
|
|
20438
|
+
if (false === options.checkout) return {
|
|
20439
|
+
name,
|
|
20440
|
+
tags,
|
|
20441
|
+
destinationPath: void 0
|
|
20442
|
+
};
|
|
20443
|
+
const directory = options.directory ?? sanitizeDirectoryName(name);
|
|
20444
|
+
if (!directory) throw new Error("App name cannot be used as a directory. Pass --directory <PATH>.");
|
|
20445
|
+
const destinationPath = external_path_default().resolve(directory);
|
|
20446
|
+
await validateCheckoutDestination(destinationPath);
|
|
20447
|
+
return {
|
|
20448
|
+
name,
|
|
20449
|
+
tags,
|
|
20450
|
+
destinationPath
|
|
20451
|
+
};
|
|
20452
|
+
}
|
|
20453
|
+
async function executeCreate(options, deps = create_defaultDeps) {
|
|
20454
|
+
const { name, tags, destinationPath } = await validateCreateInput(options);
|
|
20455
|
+
const anvilUrl = config_normalizeAnvilOrigin(options.anvilUrl ?? await resolveCheckoutUrlForApi() ?? "");
|
|
20456
|
+
const gitUrl = void 0 === options.gitUrl ? void 0 : config_normalizeAnvilOrigin(options.gitUrl);
|
|
20457
|
+
const accounts = options.user ? [] : await deps.getAccountsForUrl(anvilUrl);
|
|
20458
|
+
const username = options.user ?? accounts[0];
|
|
20459
|
+
if (!username) throw new Error(`Not logged in to ${anvilUrl}. Run 'anvil login ${anvilUrl}' and retry.`);
|
|
20460
|
+
if (!options.user && accounts.length > 1) throw new Error(`Multiple accounts found for ${anvilUrl}: ${accounts.join(", ")}. Use --user <USERNAME>.`);
|
|
20461
|
+
const authToken = await deps.getValidAuthToken(anvilUrl, username);
|
|
20462
|
+
const created = await deps.createApp({
|
|
20463
|
+
name,
|
|
20464
|
+
anvilUrl,
|
|
20465
|
+
authToken,
|
|
20466
|
+
...tags ? {
|
|
20467
|
+
tags
|
|
20468
|
+
} : {}
|
|
20469
|
+
});
|
|
20470
|
+
if (void 0 === destinationPath) return {
|
|
20471
|
+
appId: created.id,
|
|
20472
|
+
appName: created.name,
|
|
20473
|
+
anvilUrl,
|
|
20474
|
+
username,
|
|
20475
|
+
tags: created.tags ?? tags ?? [],
|
|
20476
|
+
editorUrl: `${anvilUrl}/build/apps/${encodeURIComponent(created.id)}`
|
|
20477
|
+
};
|
|
20478
|
+
try {
|
|
20479
|
+
const checkout = await deps.checkout({
|
|
20480
|
+
input: created.id,
|
|
20481
|
+
directory: destinationPath,
|
|
20482
|
+
anvilUrl,
|
|
20483
|
+
...gitUrl ? {
|
|
20484
|
+
gitUrl
|
|
20485
|
+
} : {},
|
|
20486
|
+
user: username
|
|
20487
|
+
});
|
|
20488
|
+
return {
|
|
20489
|
+
...checkout,
|
|
20490
|
+
tags: created.tags ?? tags ?? []
|
|
20491
|
+
};
|
|
20492
|
+
} catch (error) {
|
|
20493
|
+
const details = {
|
|
20494
|
+
appId: created.id,
|
|
20495
|
+
appName: created.name,
|
|
20496
|
+
anvilUrl,
|
|
20497
|
+
gitUrl,
|
|
20498
|
+
destinationPath,
|
|
20499
|
+
username,
|
|
20500
|
+
tags: created.tags ?? tags ?? []
|
|
20501
|
+
};
|
|
20502
|
+
const retry = buildShellCommandLine([
|
|
20503
|
+
"anvil",
|
|
20504
|
+
"checkout",
|
|
20505
|
+
created.id,
|
|
20506
|
+
destinationPath,
|
|
20507
|
+
"--url",
|
|
20508
|
+
anvilUrl,
|
|
20509
|
+
"--user",
|
|
20510
|
+
username,
|
|
20511
|
+
...gitUrl ? [
|
|
20512
|
+
"--git-url",
|
|
20513
|
+
gitUrl
|
|
20514
|
+
] : []
|
|
20515
|
+
]);
|
|
20516
|
+
const remainingFiles = await isDirectoryNonEmpty(destinationPath).catch(()=>true);
|
|
20517
|
+
const recovery = remainingFiles ? `Inspect the existing checkout at ${destinationPath} before retrying. For Git authentication problems, run ${buildShellCommandLine([
|
|
20518
|
+
"anvil",
|
|
20519
|
+
"git-auth",
|
|
20520
|
+
"doctor",
|
|
20521
|
+
"--repo",
|
|
20522
|
+
destinationPath
|
|
20523
|
+
])}.` : `Retry checkout with: ${retry}`;
|
|
20524
|
+
const message = errors_getErrorMessage(error).replaceAll(authToken, "[REDACTED]").replaceAll(encodeURIComponent(authToken), "[REDACTED]");
|
|
20525
|
+
throw new CreateCheckoutError(`Created app ${created.id} at ${anvilUrl}, but checkout failed: ${message}. Do not rerun create. ${recovery}`, details, {
|
|
20526
|
+
cause: error
|
|
20527
|
+
});
|
|
20528
|
+
}
|
|
20529
|
+
}
|
|
20108
20530
|
const defaultGitAuthDoctorDeps = {
|
|
20109
20531
|
getAppAuthBinding: git_auth_getAppAuthBinding,
|
|
20110
20532
|
getAccountsForUrl: auth_getAccountsForUrl,
|
|
@@ -20537,8 +20959,30 @@ print(json.dumps({"issues": issues}))
|
|
|
20537
20959
|
const response = await buildGitCredentialResponse(operation, request, options);
|
|
20538
20960
|
writeGitCredentialResponse(response);
|
|
20539
20961
|
}
|
|
20540
|
-
|
|
20541
|
-
|
|
20962
|
+
const MODEL_TOKEN_LOCK_TIMEOUT_MS = 12000;
|
|
20963
|
+
const modelToken_defaultDeps = {
|
|
20964
|
+
getValidAuthToken: auth_getValidAuthToken,
|
|
20965
|
+
readAuthFromRepo: readAuthFromRepo,
|
|
20966
|
+
cwd: ()=>process.cwd()
|
|
20967
|
+
};
|
|
20968
|
+
async function getModelToken(options = {}) {
|
|
20969
|
+
const deps = options.deps ?? modelToken_defaultDeps;
|
|
20970
|
+
const repoPath = options.repoPath ?? deps.cwd();
|
|
20971
|
+
auth_setRepoContext(repoPath);
|
|
20972
|
+
if (!process.env["ANVIL_AUTH_FILE_ENCRYPTION_KEY"]) throw new Error("ANVIL_AUTH_FILE_ENCRYPTION_KEY is not set; cannot read repo auth tokens.");
|
|
20973
|
+
const auth = await deps.readAuthFromRepo(repoPath);
|
|
20974
|
+
if (!auth) throw new Error(`No Anvil auth tokens found for the repository at ${repoPath}.`);
|
|
20975
|
+
return deps.getValidAuthToken(auth.anvilUrl, auth.username, {
|
|
20976
|
+
lock: {
|
|
20977
|
+
timeoutMs: options.lockTimeoutMs ?? MODEL_TOKEN_LOCK_TIMEOUT_MS
|
|
20978
|
+
}
|
|
20979
|
+
});
|
|
20980
|
+
}
|
|
20981
|
+
async function executeModelTokenOperation(options = {}) {
|
|
20982
|
+
const token = await getModelToken(options);
|
|
20983
|
+
process.stdout.write(`${token}\n`);
|
|
20984
|
+
}
|
|
20985
|
+
async function appDetection_decideFallbackUrl(explicitUrl, availableUrls) {
|
|
20542
20986
|
if (explicitUrl) return {
|
|
20543
20987
|
source: "explicit",
|
|
20544
20988
|
url: config_normalizeAnvilUrl(explicitUrl)
|
|
@@ -20624,7 +21068,7 @@ print(json.dumps({"issues": issues}))
|
|
|
20624
21068
|
async function resolveCheckoutUrlForApi(explicitUrl, parsedUrl) {
|
|
20625
21069
|
if (explicitUrl) return config_normalizeAnvilUrl(explicitUrl);
|
|
20626
21070
|
if (parsedUrl) return config_normalizeAnvilUrl(parsedUrl);
|
|
20627
|
-
const decision = await
|
|
21071
|
+
const decision = await appDetection_decideFallbackUrl(void 0);
|
|
20628
21072
|
if ("available-multiple" === decision.source) throw new Error(`Multiple logged-in Anvil URLs found: ${decision.urls.join(", ")}. Use --url <ANVIL_URL> to choose one.`);
|
|
20629
21073
|
return decision.url;
|
|
20630
21074
|
}
|
|
@@ -20684,7 +21128,7 @@ print(json.dumps({"issues": issues}))
|
|
|
20684
21128
|
logger_logger.verbose(external_chalk_default().cyan("Resolved app ID: ") + external_chalk_default().bold(parsed.appId));
|
|
20685
21129
|
const anvilUrl = await resolveCheckoutUrlForApi(options.anvilUrl, parsed.detectedUrl);
|
|
20686
21130
|
if (!anvilUrl) throw new Error("Anvil URL is required. Use --url <ANVIL_URL> or pass an input URL containing the host.");
|
|
20687
|
-
const gitUrl = options.gitUrl
|
|
21131
|
+
const gitUrl = void 0 === options.gitUrl ? anvilUrl : config_normalizeAnvilOrigin(options.gitUrl);
|
|
20688
21132
|
const resolvedUsername = await resolveCheckoutUsernameForApi(anvilUrl, options.user);
|
|
20689
21133
|
if (resolvedUsername) logger_logger.verbose(external_chalk_default().cyan("Using account: ") + external_chalk_default().bold(resolvedUsername));
|
|
20690
21134
|
else logger_logger.verbose(external_chalk_default().cyan("No account preselected; resolving after auth token lookup."));
|
|
@@ -20748,7 +21192,6 @@ print(json.dumps({"issues": issues}))
|
|
|
20748
21192
|
remoteName
|
|
20749
21193
|
};
|
|
20750
21194
|
}
|
|
20751
|
-
const api_DEFAULT_ANVIL_URL = resolveAnvilUrl();
|
|
20752
21195
|
async function api_checkUncommittedChanges(repoPath) {
|
|
20753
21196
|
try {
|
|
20754
21197
|
const git = esm_default(repoPath);
|
|
@@ -20797,9 +21240,10 @@ print(json.dumps({"issues": issues}))
|
|
|
20797
21240
|
}
|
|
20798
21241
|
}
|
|
20799
21242
|
async function src_api_watch(repoPath, appId, options = {}) {
|
|
20800
|
-
const { anvilUrl = api_DEFAULT_ANVIL_URL, gitUrl = anvilUrl, stagedOnly = false, username } = options;
|
|
20801
21243
|
repoPath = external_path_default().resolve(repoPath);
|
|
20802
21244
|
auth_setRepoContext(repoPath);
|
|
21245
|
+
const anvilUrl = options.anvilUrl ?? await auth_resolveAuthAnvilUrl();
|
|
21246
|
+
const { gitUrl = anvilUrl, stagedOnly = false, username } = options;
|
|
20803
21247
|
const storedEnvPid = options.environment?.envPid ? void 0 : await environment_readEnvironmentPid(repoPath);
|
|
20804
21248
|
const environment = options.environment ?? (storedEnvPid ? {
|
|
20805
21249
|
envPid: storedEnvPid
|
|
@@ -20914,6 +21358,7 @@ print(json.dumps({"issues": issues}))
|
|
|
20914
21358
|
}
|
|
20915
21359
|
})();
|
|
20916
21360
|
exports.ANVIL_SYNC_CLIENT_ID = __webpack_exports__.ANVIL_SYNC_CLIENT_ID;
|
|
21361
|
+
exports.AUTH_FILE_LOCK_DEFAULTS = __webpack_exports__.AUTH_FILE_LOCK_DEFAULTS;
|
|
20917
21362
|
exports.AnvilYamlValidationResult = __webpack_exports__.AnvilYamlValidationResult;
|
|
20918
21363
|
exports.AppIdCandidate = __webpack_exports__.AppIdCandidate;
|
|
20919
21364
|
exports.AppIdWithContext = __webpack_exports__.AppIdWithContext;
|
|
@@ -20923,13 +21368,19 @@ exports.CheckoutCloneOptions = __webpack_exports__.CheckoutCloneOptions;
|
|
|
20923
21368
|
exports.CheckoutExecutionDeps = __webpack_exports__.CheckoutExecutionDeps;
|
|
20924
21369
|
exports.CheckoutOptions = __webpack_exports__.CheckoutOptions;
|
|
20925
21370
|
exports.CheckoutResult = __webpack_exports__.CheckoutResult;
|
|
21371
|
+
exports.CreateCheckoutError = __webpack_exports__.CreateCheckoutError;
|
|
21372
|
+
exports.CreatedAnvilApp = __webpack_exports__.CreatedAnvilApp;
|
|
20926
21373
|
exports.DeviceAuthorizationResponse = __webpack_exports__.DeviceAuthorizationResponse;
|
|
20927
21374
|
exports.FormTemplateValidationResult = __webpack_exports__.FormTemplateValidationResult;
|
|
21375
|
+
exports.GetValidAuthTokenOptions = __webpack_exports__.GetValidAuthTokenOptions;
|
|
20928
21376
|
exports.LoginResult = __webpack_exports__.LoginResult;
|
|
20929
21377
|
exports.LogoutResult = __webpack_exports__.LogoutResult;
|
|
21378
|
+
exports.MODEL_TOKEN_HELPER_FILENAME = __webpack_exports__.MODEL_TOKEN_HELPER_FILENAME;
|
|
21379
|
+
exports.MODEL_TOKEN_LOCK_TIMEOUT_MS = __webpack_exports__.MODEL_TOKEN_LOCK_TIMEOUT_MS;
|
|
20930
21380
|
exports.OAuthTokenResponse = __webpack_exports__.OAuthTokenResponse;
|
|
20931
21381
|
exports.ParsedCheckoutInput = __webpack_exports__.ParsedCheckoutInput;
|
|
20932
21382
|
exports.PreferredEditor = __webpack_exports__.PreferredEditor;
|
|
21383
|
+
exports.REFRESH_REQUEST_TIMEOUT_MS = __webpack_exports__.REFRESH_REQUEST_TIMEOUT_MS;
|
|
20933
21384
|
exports.SettableConfigKey = __webpack_exports__.SettableConfigKey;
|
|
20934
21385
|
exports.TokenData = __webpack_exports__.TokenData;
|
|
20935
21386
|
exports.ValidateAppIdResponse = __webpack_exports__.ValidateAppIdResponse;
|
|
@@ -20942,6 +21393,7 @@ exports.branchFromEnvironmentVersion = __webpack_exports__.branchFromEnvironment
|
|
|
20942
21393
|
exports.buildGitAuthDoctorReport = __webpack_exports__.buildGitAuthDoctorReport;
|
|
20943
21394
|
exports.checkUncommittedChanges = __webpack_exports__.checkUncommittedChanges;
|
|
20944
21395
|
exports.clearInMemoryTokens = __webpack_exports__.clearInMemoryTokens;
|
|
21396
|
+
exports.createAnvilApp = __webpack_exports__.createAnvilApp;
|
|
20945
21397
|
exports.createCheckoutPickerSource = __webpack_exports__.createCheckoutPickerSource;
|
|
20946
21398
|
exports.createWatchDiagnostic = __webpack_exports__.createWatchDiagnostic;
|
|
20947
21399
|
exports.createWatchDiagnosticFromMessage = __webpack_exports__.createWatchDiagnosticFromMessage;
|
|
@@ -20949,7 +21401,9 @@ exports.deleteConfig = __webpack_exports__.deleteConfig;
|
|
|
20949
21401
|
exports.detectAppIdsByCommitLookup = __webpack_exports__.detectAppIdsByCommitLookup;
|
|
20950
21402
|
exports.detectAppIdsFromAllRemotes = __webpack_exports__.detectAppIdsFromAllRemotes;
|
|
20951
21403
|
exports.executeCheckout = __webpack_exports__.executeCheckout;
|
|
21404
|
+
exports.executeCreate = __webpack_exports__.executeCreate;
|
|
20952
21405
|
exports.executeGitCredentialOperation = __webpack_exports__.executeGitCredentialOperation;
|
|
21406
|
+
exports.executeModelTokenOperation = __webpack_exports__.executeModelTokenOperation;
|
|
20953
21407
|
exports.filterCandidates = __webpack_exports__.filterCandidates;
|
|
20954
21408
|
exports.formatCandidateLabel = __webpack_exports__.formatCandidateLabel;
|
|
20955
21409
|
exports.formatGitAuthDoctorReport = __webpack_exports__.formatGitAuthDoctorReport;
|
|
@@ -20963,12 +21417,15 @@ exports.getGitFetchUrl = __webpack_exports__.getGitFetchUrl;
|
|
|
20963
21417
|
exports.getGitPushUrl = __webpack_exports__.getGitPushUrl;
|
|
20964
21418
|
exports.getInstalledPreferredEditors = __webpack_exports__.getInstalledPreferredEditors;
|
|
20965
21419
|
exports.getLatestVersion = __webpack_exports__.getLatestVersion;
|
|
21420
|
+
exports.getModelToken = __webpack_exports__.getModelToken;
|
|
21421
|
+
exports.getModelTokenHelperScript = __webpack_exports__.getModelTokenHelperScript;
|
|
20966
21422
|
exports.getPreferredEditorCommand = __webpack_exports__.getPreferredEditorCommand;
|
|
20967
21423
|
exports.getSettableConfigKeys = __webpack_exports__.getSettableConfigKeys;
|
|
20968
21424
|
exports.getValidAuthToken = __webpack_exports__.getValidAuthToken;
|
|
20969
21425
|
exports.getWebSocketUrl = __webpack_exports__.getWebSocketUrl;
|
|
20970
21426
|
exports.hasTokensForUrl = __webpack_exports__.hasTokensForUrl;
|
|
20971
21427
|
exports.inspectCredentialHelperCommand = __webpack_exports__.inspectCredentialHelperCommand;
|
|
21428
|
+
exports.installModelTokenHelperScript = __webpack_exports__.installModelTokenHelperScript;
|
|
20972
21429
|
exports.isCommandAvailable = __webpack_exports__.isCommandAvailable;
|
|
20973
21430
|
exports.isDirectoryNonEmpty = __webpack_exports__.isDirectoryNonEmpty;
|
|
20974
21431
|
exports.isPathInsideGitRepo = __webpack_exports__.isPathInsideGitRepo;
|
|
@@ -21004,9 +21461,11 @@ exports.validatePath = __webpack_exports__.validatePath;
|
|
|
21004
21461
|
exports.verifyAndStoreTokens = __webpack_exports__.verifyAndStoreTokens;
|
|
21005
21462
|
exports.verifyAuth = __webpack_exports__.verifyAuth;
|
|
21006
21463
|
exports.watch = __webpack_exports__.watch;
|
|
21464
|
+
exports.withRepoAuthFileLock = __webpack_exports__.withRepoAuthFileLock;
|
|
21007
21465
|
exports.writeEnvironmentPid = __webpack_exports__.writeEnvironmentPid;
|
|
21008
21466
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
21009
21467
|
"ANVIL_SYNC_CLIENT_ID",
|
|
21468
|
+
"AUTH_FILE_LOCK_DEFAULTS",
|
|
21010
21469
|
"AnvilYamlValidationResult",
|
|
21011
21470
|
"AppIdCandidate",
|
|
21012
21471
|
"AppIdWithContext",
|
|
@@ -21016,13 +21475,19 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
21016
21475
|
"CheckoutExecutionDeps",
|
|
21017
21476
|
"CheckoutOptions",
|
|
21018
21477
|
"CheckoutResult",
|
|
21478
|
+
"CreateCheckoutError",
|
|
21479
|
+
"CreatedAnvilApp",
|
|
21019
21480
|
"DeviceAuthorizationResponse",
|
|
21020
21481
|
"FormTemplateValidationResult",
|
|
21482
|
+
"GetValidAuthTokenOptions",
|
|
21021
21483
|
"LoginResult",
|
|
21022
21484
|
"LogoutResult",
|
|
21485
|
+
"MODEL_TOKEN_HELPER_FILENAME",
|
|
21486
|
+
"MODEL_TOKEN_LOCK_TIMEOUT_MS",
|
|
21023
21487
|
"OAuthTokenResponse",
|
|
21024
21488
|
"ParsedCheckoutInput",
|
|
21025
21489
|
"PreferredEditor",
|
|
21490
|
+
"REFRESH_REQUEST_TIMEOUT_MS",
|
|
21026
21491
|
"SettableConfigKey",
|
|
21027
21492
|
"TokenData",
|
|
21028
21493
|
"ValidateAppIdResponse",
|
|
@@ -21035,6 +21500,7 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
21035
21500
|
"buildGitAuthDoctorReport",
|
|
21036
21501
|
"checkUncommittedChanges",
|
|
21037
21502
|
"clearInMemoryTokens",
|
|
21503
|
+
"createAnvilApp",
|
|
21038
21504
|
"createCheckoutPickerSource",
|
|
21039
21505
|
"createWatchDiagnostic",
|
|
21040
21506
|
"createWatchDiagnosticFromMessage",
|
|
@@ -21042,7 +21508,9 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
21042
21508
|
"detectAppIdsByCommitLookup",
|
|
21043
21509
|
"detectAppIdsFromAllRemotes",
|
|
21044
21510
|
"executeCheckout",
|
|
21511
|
+
"executeCreate",
|
|
21045
21512
|
"executeGitCredentialOperation",
|
|
21513
|
+
"executeModelTokenOperation",
|
|
21046
21514
|
"filterCandidates",
|
|
21047
21515
|
"formatCandidateLabel",
|
|
21048
21516
|
"formatGitAuthDoctorReport",
|
|
@@ -21056,12 +21524,15 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
21056
21524
|
"getGitPushUrl",
|
|
21057
21525
|
"getInstalledPreferredEditors",
|
|
21058
21526
|
"getLatestVersion",
|
|
21527
|
+
"getModelToken",
|
|
21528
|
+
"getModelTokenHelperScript",
|
|
21059
21529
|
"getPreferredEditorCommand",
|
|
21060
21530
|
"getSettableConfigKeys",
|
|
21061
21531
|
"getValidAuthToken",
|
|
21062
21532
|
"getWebSocketUrl",
|
|
21063
21533
|
"hasTokensForUrl",
|
|
21064
21534
|
"inspectCredentialHelperCommand",
|
|
21535
|
+
"installModelTokenHelperScript",
|
|
21065
21536
|
"isCommandAvailable",
|
|
21066
21537
|
"isDirectoryNonEmpty",
|
|
21067
21538
|
"isPathInsideGitRepo",
|
|
@@ -21097,6 +21568,7 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
21097
21568
|
"verifyAndStoreTokens",
|
|
21098
21569
|
"verifyAuth",
|
|
21099
21570
|
"watch",
|
|
21571
|
+
"withRepoAuthFileLock",
|
|
21100
21572
|
"writeEnvironmentPid"
|
|
21101
21573
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
21102
21574
|
Object.defineProperty(exports, '__esModule', {
|