@anvil-works/anvil-cli 0.8.0-canary.8 → 0.8.0-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/WatchSession.d.ts +2 -0
- package/dist/WatchSession.d.ts.map +1 -1
- package/dist/api.d.ts +5 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/cli.js +1583 -1068
- package/dist/commands/configure.d.ts.map +1 -1
- 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 +8 -0
- package/dist/commands/env.d.ts.map +1 -0
- package/dist/commands/index.d.ts +3 -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/watch.d.ts.map +1 -1
- package/dist/errors.d.ts +11 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/index.js +1257 -988
- package/dist/program.d.ts.map +1 -1
- 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 +7 -0
- package/dist/services/db.d.ts.map +1 -0
- package/dist/services/deps.d.ts.map +1 -1
- package/dist/services/environment.d.ts +16 -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/repl.d.ts +18 -0
- package/dist/services/repl.d.ts.map +1 -0
- 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
|
@@ -7376,15 +7376,15 @@ var __webpack_exports__ = {};
|
|
|
7376
7376
|
validateCheckoutDestination: ()=>validateCheckoutDestination,
|
|
7377
7377
|
DeviceAuthorizationResponse: ()=>oauth_login_namespaceObject.DeviceAuthorizationResponse,
|
|
7378
7378
|
OAuthTokenResponse: ()=>oauth_login_namespaceObject.OAuthTokenResponse,
|
|
7379
|
+
REFRESH_REQUEST_TIMEOUT_MS: ()=>REFRESH_REQUEST_TIMEOUT_MS,
|
|
7379
7380
|
WatchSession: ()=>WatchSession_WatchSession,
|
|
7380
7381
|
parseConfigSetValue: ()=>parseConfigSetValue,
|
|
7381
|
-
requestDeviceAuthorization: ()=>requestDeviceAuthorization,
|
|
7382
7382
|
getGitPushUrl: ()=>anvil_api_getGitPushUrl,
|
|
7383
|
+
requestDeviceAuthorization: ()=>requestDeviceAuthorization,
|
|
7383
7384
|
requireEnvironmentBranch: ()=>requireEnvironmentBranch,
|
|
7384
7385
|
setAuthTokensForAccount: ()=>setAccountTokens,
|
|
7385
|
-
validateAnvilApp: ()=>validation_validateAnvilApp,
|
|
7386
7386
|
ValidateAppIdResponse: ()=>anvil_api_namespaceObject.ValidateAppIdResponse,
|
|
7387
|
-
|
|
7387
|
+
getModelToken: ()=>getModelToken,
|
|
7388
7388
|
formatValidationPath: ()=>formatValidationPath,
|
|
7389
7389
|
resolveAnvilUrl: ()=>resolveAnvilUrl,
|
|
7390
7390
|
createCheckoutPickerSource: ()=>createCheckoutPickerSource,
|
|
@@ -7392,12 +7392,13 @@ var __webpack_exports__ = {};
|
|
|
7392
7392
|
parseCheckoutInput: ()=>parseCheckoutInput,
|
|
7393
7393
|
formatGitAuthDoctorReport: ()=>formatGitAuthDoctorReport,
|
|
7394
7394
|
resetConfig: ()=>resetConfig,
|
|
7395
|
+
MODEL_TOKEN_HELPER_FILENAME: ()=>MODEL_TOKEN_HELPER_FILENAME,
|
|
7395
7396
|
FormTemplateValidationResult: ()=>validators_namespaceObject.FormTemplateValidationResult,
|
|
7396
7397
|
createWatchDiagnostic: ()=>createWatchDiagnostic,
|
|
7397
7398
|
ValidationTarget: ()=>validators_namespaceObject.ValidationTarget,
|
|
7398
7399
|
detectAppIdsByCommitLookup: ()=>anvil_api_detectAppIdsByCommitLookup,
|
|
7399
7400
|
sanitizeDirectoryName: ()=>sanitizeDirectoryName,
|
|
7400
|
-
|
|
7401
|
+
validateAnvilApp: ()=>validation_validateAnvilApp,
|
|
7401
7402
|
LoginResult: ()=>auth_namespaceObject.LoginResult,
|
|
7402
7403
|
listAppsForCheckout: ()=>listAppsForCheckout,
|
|
7403
7404
|
getInstalledPreferredEditors: ()=>getInstalledPreferredEditors,
|
|
@@ -7406,8 +7407,11 @@ var __webpack_exports__ = {};
|
|
|
7406
7407
|
CheckoutExecutionDeps: ()=>checkout_namespaceObject.CheckoutExecutionDeps,
|
|
7407
7408
|
validateFormTemplateHtml: ()=>validateFormTemplateHtml,
|
|
7408
7409
|
ValidateBranchSyncStatusOptions: ()=>validation_namespaceObject.ValidateBranchSyncStatusOptions,
|
|
7410
|
+
validatePath: ()=>validatePath,
|
|
7411
|
+
withRepoAuthFileLock: ()=>withRepoAuthFileLock,
|
|
7409
7412
|
BranchSyncStatus: ()=>validation_namespaceObject.BranchSyncStatus,
|
|
7410
7413
|
getLatestVersion: ()=>getLatestVersion,
|
|
7414
|
+
getModelTokenHelperScript: ()=>getModelTokenHelperScript,
|
|
7411
7415
|
isDirectoryNonEmpty: ()=>isDirectoryNonEmpty,
|
|
7412
7416
|
syncToLatest: ()=>src_api_syncToLatest,
|
|
7413
7417
|
filterCandidates: ()=>anvil_api_filterCandidates,
|
|
@@ -7416,7 +7420,7 @@ var __webpack_exports__ = {};
|
|
|
7416
7420
|
isPathInsideGitRepo: ()=>isPathInsideGitRepo,
|
|
7417
7421
|
normalizeAnvilUrl: ()=>config_normalizeAnvilUrl,
|
|
7418
7422
|
ValidationIssue: ()=>validators_namespaceObject.ValidationIssue,
|
|
7419
|
-
|
|
7423
|
+
verifyAndStoreTokens: ()=>auth_verifyAndStoreTokens,
|
|
7420
7424
|
readEnvironmentPid: ()=>environment_readEnvironmentPid,
|
|
7421
7425
|
validateFormTemplate: ()=>validateFormTemplate,
|
|
7422
7426
|
preferredEditors: ()=>preferredEditors,
|
|
@@ -7428,12 +7432,14 @@ var __webpack_exports__ = {};
|
|
|
7428
7432
|
validateBranchSyncStatus: ()=>validation_validateBranchSyncStatus,
|
|
7429
7433
|
checkUncommittedChanges: ()=>api_checkUncommittedChanges,
|
|
7430
7434
|
hasTokensForUrl: ()=>auth_hasTokensForUrl,
|
|
7435
|
+
writeEnvironmentPid: ()=>writeEnvironmentPid,
|
|
7431
7436
|
AnvilYamlValidationResult: ()=>validators_namespaceObject.AnvilYamlValidationResult,
|
|
7432
7437
|
ValidatePathResult: ()=>validators_namespaceObject.ValidatePathResult,
|
|
7433
7438
|
getSettableConfigKeys: ()=>getSettableConfigKeys,
|
|
7434
7439
|
logout: ()=>logout,
|
|
7435
7440
|
TokenData: ()=>auth_namespaceObject.TokenData,
|
|
7436
7441
|
detectAppIdsFromAllRemotes: ()=>anvil_api_detectAppIdsFromAllRemotes,
|
|
7442
|
+
executeModelTokenOperation: ()=>executeModelTokenOperation,
|
|
7437
7443
|
getWebSocketUrl: ()=>getWebSocketUrl,
|
|
7438
7444
|
getAllConfig: ()=>getAllConfig,
|
|
7439
7445
|
isCommandAvailable: ()=>config_isCommandAvailable,
|
|
@@ -7443,6 +7449,7 @@ var __webpack_exports__ = {};
|
|
|
7443
7449
|
getValidAuthToken: ()=>auth_getValidAuthToken,
|
|
7444
7450
|
watch: ()=>src_api_watch,
|
|
7445
7451
|
deleteConfig: ()=>deleteConfig,
|
|
7452
|
+
installModelTokenHelperScript: ()=>installModelTokenHelperScript,
|
|
7446
7453
|
getGitFetchUrl: ()=>anvil_api_getGitFetchUrl,
|
|
7447
7454
|
PreferredEditor: ()=>config_namespaceObject.PreferredEditor,
|
|
7448
7455
|
getAvailableAnvilUrls: ()=>getAvailableAnvilUrls,
|
|
@@ -7455,8 +7462,11 @@ var __webpack_exports__ = {};
|
|
|
7455
7462
|
CheckoutResult: ()=>checkout_namespaceObject.CheckoutResult,
|
|
7456
7463
|
ParsedCheckoutInput: ()=>checkout_namespaceObject.ParsedCheckoutInput,
|
|
7457
7464
|
parseCredentialHelperCommand: ()=>parseCredentialHelperCommand,
|
|
7465
|
+
MODEL_TOKEN_LOCK_TIMEOUT_MS: ()=>MODEL_TOKEN_LOCK_TIMEOUT_MS,
|
|
7466
|
+
GetValidAuthTokenOptions: ()=>auth_namespaceObject.GetValidAuthTokenOptions,
|
|
7458
7467
|
clearInMemoryTokens: ()=>clearInMemoryTokens,
|
|
7459
7468
|
getDefaultDestinationDirectory: ()=>getDefaultDestinationDirectory,
|
|
7469
|
+
AUTH_FILE_LOCK_DEFAULTS: ()=>AUTH_FILE_LOCK_DEFAULTS,
|
|
7460
7470
|
lookupByCommit: ()=>lookupByCommit,
|
|
7461
7471
|
AppIdCandidate: ()=>anvil_api_namespaceObject.AppIdCandidate,
|
|
7462
7472
|
verifyAuth: ()=>auth_verifyAuth
|
|
@@ -7485,12 +7495,14 @@ var __webpack_exports__ = {};
|
|
|
7485
7495
|
__webpack_require__.r(auth_namespaceObject);
|
|
7486
7496
|
__webpack_require__.d(auth_namespaceObject, {
|
|
7487
7497
|
fg: ()=>ANVIL_SYNC_CLIENT_ID,
|
|
7498
|
+
ru: ()=>REFRESH_REQUEST_TIMEOUT_MS,
|
|
7488
7499
|
Ou: ()=>clearInMemoryTokens,
|
|
7489
7500
|
Fr: ()=>auth_getAccountsForUrl,
|
|
7490
7501
|
u5: ()=>getAvailableAnvilUrls,
|
|
7491
7502
|
_p: ()=>auth_getValidAuthToken,
|
|
7492
7503
|
Fi: ()=>auth_hasTokensForUrl,
|
|
7493
7504
|
ri: ()=>logout,
|
|
7505
|
+
UE: ()=>auth_resolveAuthAnvilUrl,
|
|
7494
7506
|
f5: ()=>setInMemoryTokens,
|
|
7495
7507
|
iT: ()=>auth_setRepoContext,
|
|
7496
7508
|
CQ: ()=>auth_verifyAndStoreTokens,
|
|
@@ -13365,9 +13377,10 @@ var __webpack_exports__ = {};
|
|
|
13365
13377
|
type: "auth_invalid",
|
|
13366
13378
|
message
|
|
13367
13379
|
}),
|
|
13368
|
-
refreshFailed: (message)=>({
|
|
13380
|
+
refreshFailed: (message, status)=>({
|
|
13369
13381
|
type: "token_refresh_failed",
|
|
13370
|
-
message
|
|
13382
|
+
message,
|
|
13383
|
+
status
|
|
13371
13384
|
})
|
|
13372
13385
|
};
|
|
13373
13386
|
const createAppError = {
|
|
@@ -13584,6 +13597,7 @@ var __webpack_exports__ = {};
|
|
|
13584
13597
|
const external_module_namespaceObject = require("module");
|
|
13585
13598
|
const requireFromHere = (0, external_module_namespaceObject.createRequire)(__filename);
|
|
13586
13599
|
const GIT_CREDENTIAL_HELPER_FILENAME = "anvil-credential-helper.cjs";
|
|
13600
|
+
const MODEL_TOKEN_HELPER_FILENAME = "anvil-model-token-helper.cjs";
|
|
13587
13601
|
const GIT_CREDENTIAL_HELPER_LOCATOR = `$(git rev-parse --git-common-dir)/${GIT_CREDENTIAL_HELPER_FILENAME}`;
|
|
13588
13602
|
function getUrlConfigKey(appId) {
|
|
13589
13603
|
return `anvil.auth.${appId}.url`;
|
|
@@ -13674,6 +13688,38 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13674
13688
|
});
|
|
13675
13689
|
`;
|
|
13676
13690
|
}
|
|
13691
|
+
function getModelTokenHelperScript(modulePath) {
|
|
13692
|
+
return `#!/usr/bin/env node
|
|
13693
|
+
"use strict";
|
|
13694
|
+
|
|
13695
|
+
const { execFileSync } = require("child_process");
|
|
13696
|
+
const { executeModelTokenOperation } = require(${JSON.stringify(modulePath)});
|
|
13697
|
+
|
|
13698
|
+
function resolveRepoPath() {
|
|
13699
|
+
return execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
13700
|
+
cwd: process.cwd(),
|
|
13701
|
+
encoding: "utf8",
|
|
13702
|
+
}).trim();
|
|
13703
|
+
}
|
|
13704
|
+
|
|
13705
|
+
Promise.resolve()
|
|
13706
|
+
.then(() => executeModelTokenOperation({ repoPath: resolveRepoPath() }))
|
|
13707
|
+
.catch((e) => {
|
|
13708
|
+
process.stderr.write("anvil model token helper failed: " + ((e && e.message) || e) + "\\n");
|
|
13709
|
+
process.exit(1);
|
|
13710
|
+
});
|
|
13711
|
+
`;
|
|
13712
|
+
}
|
|
13713
|
+
async function installModelTokenHelperScript(helperPath, options) {
|
|
13714
|
+
await external_fs_.promises.mkdir(external_path_default().dirname(helperPath), {
|
|
13715
|
+
recursive: true
|
|
13716
|
+
});
|
|
13717
|
+
await external_fs_.promises.writeFile(helperPath, getModelTokenHelperScript(options?.modulePath ?? getCredentialHelperModulePath()), {
|
|
13718
|
+
mode: 448
|
|
13719
|
+
});
|
|
13720
|
+
await external_fs_.promises.chmod(helperPath, 448);
|
|
13721
|
+
return helperPath;
|
|
13722
|
+
}
|
|
13677
13723
|
function findPackageRoot(startPath) {
|
|
13678
13724
|
let dir = external_fs_default().existsSync(startPath) && external_fs_default().statSync(startPath).isDirectory() ? startPath : external_path_default().dirname(startPath);
|
|
13679
13725
|
while(true){
|
|
@@ -13801,6 +13847,76 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13801
13847
|
function getAuthFilePath(gitDir) {
|
|
13802
13848
|
return external_path_default().join(gitDir, "anvil-auth.json");
|
|
13803
13849
|
}
|
|
13850
|
+
const AUTH_FILE_LOCK_DEFAULTS = {
|
|
13851
|
+
staleMs: 30000,
|
|
13852
|
+
timeoutMs: 60000,
|
|
13853
|
+
retryDelayMs: 100,
|
|
13854
|
+
heartbeatMs: 5000
|
|
13855
|
+
};
|
|
13856
|
+
function git_auth_delay(ms) {
|
|
13857
|
+
return new Promise((resolve)=>setTimeout(resolve, ms));
|
|
13858
|
+
}
|
|
13859
|
+
async function acquireAuthFileLock(lockPath, options) {
|
|
13860
|
+
const deadline = Date.now() + options.timeoutMs;
|
|
13861
|
+
while(true){
|
|
13862
|
+
try {
|
|
13863
|
+
const handle = await external_fs_.promises.open(lockPath, "wx", 384);
|
|
13864
|
+
try {
|
|
13865
|
+
await handle.writeFile(JSON.stringify({
|
|
13866
|
+
pid: process.pid,
|
|
13867
|
+
acquiredAt: new Date().toISOString()
|
|
13868
|
+
}));
|
|
13869
|
+
} finally{
|
|
13870
|
+
await handle.close();
|
|
13871
|
+
}
|
|
13872
|
+
return;
|
|
13873
|
+
} catch (e) {
|
|
13874
|
+
if ("EEXIST" !== e.code) throw e;
|
|
13875
|
+
}
|
|
13876
|
+
try {
|
|
13877
|
+
const lockStat = await external_fs_.promises.stat(lockPath);
|
|
13878
|
+
if (Date.now() - lockStat.mtimeMs > options.staleMs) {
|
|
13879
|
+
await external_fs_.promises.rm(lockPath, {
|
|
13880
|
+
force: true
|
|
13881
|
+
});
|
|
13882
|
+
continue;
|
|
13883
|
+
}
|
|
13884
|
+
} catch {
|
|
13885
|
+
continue;
|
|
13886
|
+
}
|
|
13887
|
+
if (Date.now() >= deadline) throw new Error(`Timed out waiting for the Anvil auth file lock at ${lockPath}`);
|
|
13888
|
+
await git_auth_delay(options.retryDelayMs);
|
|
13889
|
+
}
|
|
13890
|
+
}
|
|
13891
|
+
async function withRepoAuthFileLock(repoPath, fn, options) {
|
|
13892
|
+
const gitDir = await getRepositoryGitDir(repoPath);
|
|
13893
|
+
const lockPath = `${getAuthFilePath(gitDir)}.lock`;
|
|
13894
|
+
const lockOptions = {
|
|
13895
|
+
...AUTH_FILE_LOCK_DEFAULTS,
|
|
13896
|
+
...options
|
|
13897
|
+
};
|
|
13898
|
+
await external_fs_.promises.mkdir(external_path_default().dirname(lockPath), {
|
|
13899
|
+
recursive: true
|
|
13900
|
+
});
|
|
13901
|
+
await acquireAuthFileLock(lockPath, lockOptions);
|
|
13902
|
+
const heartbeat = startAuthFileLockHeartbeat(lockPath, lockOptions.heartbeatMs);
|
|
13903
|
+
try {
|
|
13904
|
+
return await fn();
|
|
13905
|
+
} finally{
|
|
13906
|
+
clearInterval(heartbeat);
|
|
13907
|
+
await external_fs_.promises.rm(lockPath, {
|
|
13908
|
+
force: true
|
|
13909
|
+
});
|
|
13910
|
+
}
|
|
13911
|
+
}
|
|
13912
|
+
function startAuthFileLockHeartbeat(lockPath, heartbeatMs) {
|
|
13913
|
+
const heartbeat = setInterval(()=>{
|
|
13914
|
+
const now = new Date();
|
|
13915
|
+
external_fs_.promises.utimes(lockPath, now, now).catch(()=>{});
|
|
13916
|
+
}, heartbeatMs);
|
|
13917
|
+
heartbeat.unref();
|
|
13918
|
+
return heartbeat;
|
|
13919
|
+
}
|
|
13804
13920
|
function decodeKey(b64key) {
|
|
13805
13921
|
const key = Buffer.from(b64key, "base64");
|
|
13806
13922
|
if (32 !== key.length) throw new Error("Encryption key must be a base64-encoded 32-byte key");
|
|
@@ -13845,10 +13961,19 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13845
13961
|
recursive: true
|
|
13846
13962
|
});
|
|
13847
13963
|
const authJson = JSON.stringify(auth, null, 2);
|
|
13848
|
-
|
|
13849
|
-
|
|
13850
|
-
|
|
13851
|
-
|
|
13964
|
+
const tempFilePath = `${authFilePath}.tmp-${external_node_crypto_default().randomBytes(6).toString("hex")}`;
|
|
13965
|
+
try {
|
|
13966
|
+
await external_fs_.promises.writeFile(tempFilePath, encrypt(authJson, encryptionKey), {
|
|
13967
|
+
mode: 384
|
|
13968
|
+
});
|
|
13969
|
+
await external_fs_.promises.chmod(tempFilePath, 448);
|
|
13970
|
+
await external_fs_.promises.rename(tempFilePath, authFilePath);
|
|
13971
|
+
} catch (e) {
|
|
13972
|
+
await external_fs_.promises.rm(tempFilePath, {
|
|
13973
|
+
force: true
|
|
13974
|
+
});
|
|
13975
|
+
throw e;
|
|
13976
|
+
}
|
|
13852
13977
|
await git.raw([
|
|
13853
13978
|
"config",
|
|
13854
13979
|
"--local",
|
|
@@ -13859,6 +13984,7 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13859
13984
|
}
|
|
13860
13985
|
const readAuthFromRepo = async (repoPath)=>{
|
|
13861
13986
|
const git = esm_default(repoPath);
|
|
13987
|
+
if (!await git.checkIsRepo()) return;
|
|
13862
13988
|
const gitDir = await getRepositoryGitDir(repoPath, git);
|
|
13863
13989
|
const authFilePath = getAuthFilePath(gitDir);
|
|
13864
13990
|
if (!external_fs_default().existsSync(authFilePath)) return;
|
|
@@ -13870,6 +13996,7 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13870
13996
|
return resolveAnvilUrl();
|
|
13871
13997
|
}
|
|
13872
13998
|
const ANVIL_SYNC_CLIENT_ID = "anvil-sync";
|
|
13999
|
+
const REFRESH_REQUEST_TIMEOUT_MS = 12000;
|
|
13873
14000
|
let inMemoryAuth = null;
|
|
13874
14001
|
function setInMemoryTokens(anvilUrl, username, tokens) {
|
|
13875
14002
|
inMemoryAuth = {
|
|
@@ -13888,6 +14015,11 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13888
14015
|
function auth_setRepoContext(repoPath) {
|
|
13889
14016
|
repoContext = repoPath;
|
|
13890
14017
|
}
|
|
14018
|
+
async function auth_resolveAuthAnvilUrl() {
|
|
14019
|
+
if (inMemoryAuth) return inMemoryAuth.anvilUrl;
|
|
14020
|
+
const repoAuth = repoContext ? await readAuthFromRepo(repoContext) : void 0;
|
|
14021
|
+
return repoAuth?.anvilUrl ?? resolveAnvilUrl();
|
|
14022
|
+
}
|
|
13891
14023
|
const inFlightRefreshes = new Map();
|
|
13892
14024
|
async function auth_verifyAuth(authToken, anvilUrl = getDefaultAnvilUrl()) {
|
|
13893
14025
|
try {
|
|
@@ -13908,7 +14040,7 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13908
14040
|
throw createAuthError.invalid(`Network error: ${e.message}`);
|
|
13909
14041
|
}
|
|
13910
14042
|
}
|
|
13911
|
-
async function refreshAccessToken(refreshToken, anvilUrl = getDefaultAnvilUrl(), clientId = ANVIL_SYNC_CLIENT_ID) {
|
|
14043
|
+
async function refreshAccessToken(refreshToken, anvilUrl = getDefaultAnvilUrl(), clientId = ANVIL_SYNC_CLIENT_ID, options) {
|
|
13912
14044
|
try {
|
|
13913
14045
|
const tokenResponse = await fetch(`${anvilUrl}/oauth/token`, {
|
|
13914
14046
|
method: "POST",
|
|
@@ -13919,11 +14051,12 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13919
14051
|
grant_type: "refresh_token",
|
|
13920
14052
|
refresh_token: refreshToken,
|
|
13921
14053
|
client_id: clientId
|
|
13922
|
-
})
|
|
14054
|
+
}),
|
|
14055
|
+
signal: AbortSignal.timeout(options?.timeoutMs ?? REFRESH_REQUEST_TIMEOUT_MS)
|
|
13923
14056
|
});
|
|
13924
14057
|
if (!tokenResponse.ok) {
|
|
13925
14058
|
const errorText = await tokenResponse.text();
|
|
13926
|
-
throw createAuthError.refreshFailed(`Failed to refresh token: ${tokenResponse.status} ${errorText}
|
|
14059
|
+
throw createAuthError.refreshFailed(`Failed to refresh token: ${tokenResponse.status} ${errorText}`, tokenResponse.status);
|
|
13927
14060
|
}
|
|
13928
14061
|
const tokenData = await tokenResponse.json();
|
|
13929
14062
|
return tokenData;
|
|
@@ -13940,17 +14073,16 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13940
14073
|
return hasTokens(anvilUrl, username);
|
|
13941
14074
|
}
|
|
13942
14075
|
}
|
|
13943
|
-
async function auth_getValidAuthToken(anvilUrl = getDefaultAnvilUrl(), username) {
|
|
14076
|
+
async function auth_getValidAuthToken(anvilUrl = getDefaultAnvilUrl(), username, options) {
|
|
13944
14077
|
const normalized = config_normalizeAnvilUrl(anvilUrl);
|
|
13945
14078
|
const source = await resolveTokenSource(normalized, username);
|
|
13946
14079
|
const tokens = getSourceTokens(source);
|
|
13947
14080
|
if (!tokens.authToken && !tokens.refreshToken) throw createAuthError.required("Not logged in. Please log in first.");
|
|
13948
|
-
|
|
13949
|
-
if (tokens.refreshToken && isExpired) {
|
|
14081
|
+
if (tokens.refreshToken && isAccessTokenExpired(tokens)) {
|
|
13950
14082
|
const refreshKey = getRefreshKey(normalized, username, source, tokens.refreshToken);
|
|
13951
14083
|
const existingRefresh = inFlightRefreshes.get(refreshKey);
|
|
13952
14084
|
if (existingRefresh) return existingRefresh;
|
|
13953
|
-
const refreshPromise = refreshAndStoreAccessToken(normalized, username, source, tokens.refreshToken).finally(()=>{
|
|
14085
|
+
const refreshPromise = refreshAndStoreAccessToken(normalized, username, source, tokens.refreshToken, options).finally(()=>{
|
|
13954
14086
|
inFlightRefreshes.delete(refreshKey);
|
|
13955
14087
|
});
|
|
13956
14088
|
inFlightRefreshes.set(refreshKey, refreshPromise);
|
|
@@ -13980,6 +14112,9 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13980
14112
|
function getSourceTokens(source) {
|
|
13981
14113
|
return "store" === source.type ? source.tokens : source.auth.tokens;
|
|
13982
14114
|
}
|
|
14115
|
+
function isAccessTokenExpired(tokens) {
|
|
14116
|
+
return null !== tokens.authTokenExpiresAt && tokens.authTokenExpiresAt <= Math.floor(Date.now() / 1000) + 60;
|
|
14117
|
+
}
|
|
13983
14118
|
function getStoreAccountUsername(normalizedUrl, username, refreshToken) {
|
|
13984
14119
|
if (username) return username;
|
|
13985
14120
|
const urlTokens = getUrlTokens(normalizedUrl);
|
|
@@ -13998,11 +14133,43 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
13998
14133
|
return `store:${normalizedUrl}:${source.accountUsername ?? username ?? refreshToken}`;
|
|
13999
14134
|
}
|
|
14000
14135
|
}
|
|
14001
|
-
async function refreshAndStoreAccessToken(normalizedUrl, username, source, refreshToken) {
|
|
14136
|
+
async function refreshAndStoreAccessToken(normalizedUrl, username, source, refreshToken, options) {
|
|
14137
|
+
if ("repo" === source.type) return refreshRepoAuthTokens(source.repoPath, {
|
|
14138
|
+
anvilUrl: normalizedUrl,
|
|
14139
|
+
username,
|
|
14140
|
+
auth: source.auth,
|
|
14141
|
+
refreshToken,
|
|
14142
|
+
lock: options?.lock,
|
|
14143
|
+
requestTimeoutMs: options?.requestTimeoutMs
|
|
14144
|
+
});
|
|
14145
|
+
return performTokenRefresh(normalizedUrl, username, source, refreshToken, options?.requestTimeoutMs);
|
|
14146
|
+
}
|
|
14147
|
+
async function refreshRepoAuthTokens(repoPath, options) {
|
|
14148
|
+
const normalizedUrl = config_normalizeAnvilUrl(options.anvilUrl);
|
|
14149
|
+
return withRepoAuthFileLock(repoPath, async ()=>{
|
|
14150
|
+
let auth = options.auth;
|
|
14151
|
+
let refreshToken = options.refreshToken;
|
|
14152
|
+
const current = await readAuthFromRepo(repoPath);
|
|
14153
|
+
if (current && authMatches(current, normalizedUrl, options.username)) {
|
|
14154
|
+
if (current.tokens.authToken && !isAccessTokenExpired(current.tokens)) return current.tokens.authToken;
|
|
14155
|
+
auth = current;
|
|
14156
|
+
refreshToken = current.tokens.refreshToken ?? refreshToken;
|
|
14157
|
+
}
|
|
14158
|
+
if (!auth || !refreshToken) throw createAuthError.required("No repo auth tokens available to refresh.");
|
|
14159
|
+
return performTokenRefresh(normalizedUrl, options.username, {
|
|
14160
|
+
type: "repo",
|
|
14161
|
+
auth,
|
|
14162
|
+
repoPath
|
|
14163
|
+
}, refreshToken, options.requestTimeoutMs);
|
|
14164
|
+
}, options.lock);
|
|
14165
|
+
}
|
|
14166
|
+
async function performTokenRefresh(normalizedUrl, username, source, refreshToken, requestTimeoutMs) {
|
|
14002
14167
|
try {
|
|
14003
14168
|
const tokens = getSourceTokens(source);
|
|
14004
14169
|
const clientId = tokens.clientId ?? ANVIL_SYNC_CLIENT_ID;
|
|
14005
|
-
const tokenData = await refreshAccessToken(refreshToken, normalizedUrl, clientId
|
|
14170
|
+
const tokenData = await refreshAccessToken(refreshToken, normalizedUrl, clientId, {
|
|
14171
|
+
timeoutMs: requestTimeoutMs
|
|
14172
|
+
});
|
|
14006
14173
|
const newTokens = {
|
|
14007
14174
|
authToken: tokenData.access_token,
|
|
14008
14175
|
refreshToken: tokenData.refresh_token,
|
|
@@ -14024,10 +14191,26 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
14024
14191
|
}
|
|
14025
14192
|
return tokenData.access_token;
|
|
14026
14193
|
} catch (e) {
|
|
14194
|
+
if ("repo" === source.type && isRefreshTokenRejection(e)) await clearRepoAuthTokens(source.repoPath, source.auth).catch(()=>{});
|
|
14027
14195
|
await clearTokensForAccount(normalizedUrl, username, refreshToken);
|
|
14028
14196
|
throw e;
|
|
14029
14197
|
}
|
|
14030
14198
|
}
|
|
14199
|
+
function isRefreshTokenRejection(e) {
|
|
14200
|
+
const error = e;
|
|
14201
|
+
return error?.type === "token_refresh_failed" && (400 === error.status || 401 === error.status);
|
|
14202
|
+
}
|
|
14203
|
+
async function clearRepoAuthTokens(repoPath, auth) {
|
|
14204
|
+
const encryptionKey = process.env["ANVIL_AUTH_FILE_ENCRYPTION_KEY"];
|
|
14205
|
+
if (!encryptionKey) return;
|
|
14206
|
+
auth.tokens = {
|
|
14207
|
+
authToken: null,
|
|
14208
|
+
refreshToken: null,
|
|
14209
|
+
authTokenExpiresAt: null,
|
|
14210
|
+
clientId: auth.tokens.clientId
|
|
14211
|
+
};
|
|
14212
|
+
await writeAuthToFile(repoPath, auth, encryptionKey);
|
|
14213
|
+
}
|
|
14031
14214
|
async function clearTokensForAccount(url, username, refreshToken) {
|
|
14032
14215
|
if (inMemoryAuth || repoContext && await readAuthFromRepo(repoContext)) return;
|
|
14033
14216
|
{
|
|
@@ -14109,1042 +14292,1074 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
|
|
|
14109
14292
|
return getAvailableUrls();
|
|
14110
14293
|
}
|
|
14111
14294
|
}
|
|
14112
|
-
|
|
14113
|
-
|
|
14295
|
+
const promises_namespaceObject = require("timers/promises");
|
|
14296
|
+
const WANT_NOT_VALID_RE = /\bwant\s+[0-9a-f]{7,40}\s+not valid\b/i;
|
|
14297
|
+
const FETCH_RETRY_DELAY_MS = 200;
|
|
14298
|
+
function isWantNotValidError(error) {
|
|
14299
|
+
return WANT_NOT_VALID_RE.test(error.message || "");
|
|
14114
14300
|
}
|
|
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);
|
|
14301
|
+
class git_GitService extends Emitter {
|
|
14302
|
+
git;
|
|
14303
|
+
repoPath;
|
|
14304
|
+
static INDEX_LOCK_RETRY_DELAYS_MS = [
|
|
14305
|
+
25,
|
|
14306
|
+
50,
|
|
14307
|
+
100,
|
|
14308
|
+
200
|
|
14309
|
+
];
|
|
14310
|
+
constructor(repoPath){
|
|
14311
|
+
super();
|
|
14312
|
+
this.repoPath = external_path_default().resolve(repoPath);
|
|
14313
|
+
this.git = esm_default(this.repoPath);
|
|
14144
14314
|
}
|
|
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);
|
|
14315
|
+
getGit() {
|
|
14316
|
+
return this.git;
|
|
14317
|
+
}
|
|
14318
|
+
getRepoPath() {
|
|
14319
|
+
return this.repoPath;
|
|
14320
|
+
}
|
|
14321
|
+
async getGitDir() {
|
|
14322
|
+
try {
|
|
14323
|
+
const gitDir = (await this.git.revparse([
|
|
14324
|
+
"--git-dir"
|
|
14325
|
+
])).trim();
|
|
14326
|
+
if (!external_path_default().isAbsolute(gitDir)) return external_path_default().resolve(this.repoPath, gitDir);
|
|
14327
|
+
return gitDir;
|
|
14328
|
+
} catch (e) {
|
|
14329
|
+
throw errors_createGitError.commandFailed("rev-parse --git-dir", e.message);
|
|
14163
14330
|
}
|
|
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
14331
|
}
|
|
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);
|
|
14332
|
+
async getCurrentBranch() {
|
|
14333
|
+
try {
|
|
14334
|
+
const branchRef = await this.git.revparse([
|
|
14335
|
+
"--abbrev-ref",
|
|
14336
|
+
"HEAD"
|
|
14337
|
+
]);
|
|
14338
|
+
if ("HEAD" === branchRef) throw createSyncError.detachedHead();
|
|
14339
|
+
return branchRef;
|
|
14340
|
+
} catch (e) {
|
|
14341
|
+
if ("detached_head" === e.type) throw e;
|
|
14342
|
+
throw createSyncError.detachedHead();
|
|
14191
14343
|
}
|
|
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
14344
|
}
|
|
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);
|
|
14345
|
+
async getCommitId() {
|
|
14346
|
+
try {
|
|
14347
|
+
const commitId = (await this.git.revparse([
|
|
14348
|
+
"HEAD"
|
|
14349
|
+
])).trim();
|
|
14350
|
+
return commitId;
|
|
14351
|
+
} catch (e) {
|
|
14352
|
+
throw errors_createGitError.commandFailed("revparse", e.message);
|
|
14353
|
+
}
|
|
14224
14354
|
}
|
|
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}`);
|
|
14345
|
-
}
|
|
14346
|
-
if (resp.ok) {
|
|
14347
|
-
const data = await resp.json();
|
|
14348
|
-
logger_logger.debug(`data ${JSON.stringify(data)}`);
|
|
14349
|
-
const apps = data?.apps ?? [];
|
|
14350
|
-
for (const app of apps)if (app?.app_id) out.push({
|
|
14351
|
-
appId: app.app_id,
|
|
14352
|
-
source: "remote",
|
|
14353
|
-
description: `Reverse lookup by commit${app.branch ? ` on branch '${app.branch}'` : ""}`
|
|
14354
|
-
});
|
|
14355
|
+
async getCommitInfo() {
|
|
14356
|
+
try {
|
|
14357
|
+
const hash = (await this.git.revparse([
|
|
14358
|
+
"HEAD"
|
|
14359
|
+
])).trim();
|
|
14360
|
+
const message = (await this.git.raw([
|
|
14361
|
+
"log",
|
|
14362
|
+
"-1",
|
|
14363
|
+
"--format=%s"
|
|
14364
|
+
])).trim();
|
|
14365
|
+
return {
|
|
14366
|
+
hash,
|
|
14367
|
+
shortHash: hash.substring(0, 8),
|
|
14368
|
+
message
|
|
14369
|
+
};
|
|
14370
|
+
} catch (e) {
|
|
14371
|
+
throw errors_createGitError.commandFailed("log", e.message);
|
|
14355
14372
|
}
|
|
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
|
-
}
|
|
14383
|
-
const keysA = Object.keys(a);
|
|
14384
|
-
const keysB = Object.keys(b);
|
|
14385
|
-
if (keysA.length !== keysB.length) return false;
|
|
14386
|
-
return keysA.every((key)=>deepEqual(a[key], b[key]));
|
|
14387
|
-
}
|
|
14388
|
-
function parseHtmlWithFrontmatter(htmlContent) {
|
|
14389
|
-
const frontmatterPattern = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
|
|
14390
|
-
const match = htmlContent.match(frontmatterPattern);
|
|
14391
|
-
if (match) {
|
|
14392
|
-
const yamlStr = match[1];
|
|
14393
|
-
const html = match[2];
|
|
14394
|
-
const frontmatter = yamlStr ? external_js_yaml_default().load(yamlStr) ?? {} : {};
|
|
14395
|
-
return {
|
|
14396
|
-
frontmatter,
|
|
14397
|
-
html
|
|
14398
|
-
};
|
|
14399
14373
|
}
|
|
14400
|
-
|
|
14401
|
-
|
|
14402
|
-
|
|
14403
|
-
|
|
14404
|
-
|
|
14405
|
-
|
|
14406
|
-
|
|
14407
|
-
|
|
14408
|
-
|
|
14409
|
-
|
|
14410
|
-
|
|
14411
|
-
|
|
14412
|
-
|
|
14413
|
-
|
|
14414
|
-
|
|
14415
|
-
|
|
14416
|
-
|
|
14417
|
-
|
|
14418
|
-
|
|
14419
|
-
}
|
|
14420
|
-
const ANVIL_DEPS_DIR = ".anvil/deps";
|
|
14421
|
-
const ANVIL_DEPS_MANIFEST = "manifest.json";
|
|
14422
|
-
const DEPS_MANIFEST_VERSION = 2;
|
|
14423
|
-
function formatFetchError(prefix, status, errorBody) {
|
|
14424
|
-
if (!errorBody) return `${prefix}: ${status}`;
|
|
14425
|
-
try {
|
|
14426
|
-
const parsed = JSON.parse(errorBody);
|
|
14427
|
-
if ("string" == typeof parsed.error && parsed.error.trim()) return `${prefix}: ${parsed.error} (${status})`;
|
|
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));
|
|
14450
|
-
}
|
|
14451
|
-
return await resp.json();
|
|
14452
|
-
}
|
|
14453
|
-
async function refreshDependencyCache(projectRoot, appId, anvilUrl = resolveAnvilUrl(), options = {}) {
|
|
14454
|
-
const includeDocs = options.includeDocs ?? true;
|
|
14455
|
-
const knownDependencies = await getKnownDependenciesForCache(projectRoot, includeDocs);
|
|
14456
|
-
const response = await fetchAllDependencies(appId, anvilUrl, {
|
|
14457
|
-
commit: options.commit,
|
|
14458
|
-
includeDocs,
|
|
14459
|
-
knownDependencies
|
|
14460
|
-
});
|
|
14461
|
-
if (!response.resolved_dependencies.length) {
|
|
14462
|
-
await clearDepsCache(projectRoot);
|
|
14463
|
-
return {
|
|
14464
|
-
response,
|
|
14465
|
-
addedGitignoreEntry: false
|
|
14466
|
-
};
|
|
14467
|
-
}
|
|
14468
|
-
const addedGitignoreEntry = await ensureProjectGitignoreIgnoresAnvilDir(projectRoot);
|
|
14469
|
-
await writeAllDepsToCache(projectRoot, response, {
|
|
14470
|
-
includeDocs
|
|
14471
|
-
});
|
|
14472
|
-
return {
|
|
14473
|
-
response,
|
|
14474
|
-
addedGitignoreEntry
|
|
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;
|
|
14374
|
+
async getStatus() {
|
|
14375
|
+
try {
|
|
14376
|
+
const status = await this.git.status();
|
|
14377
|
+
const staged = status.files.filter((file)=>{
|
|
14378
|
+
const indexStatus = file.index.trim();
|
|
14379
|
+
return indexStatus.length > 0 && "?" !== indexStatus;
|
|
14380
|
+
}).map((file)=>file.path);
|
|
14381
|
+
return {
|
|
14382
|
+
isClean: status.isClean(),
|
|
14383
|
+
modified: status.modified,
|
|
14384
|
+
notAdded: status.not_added,
|
|
14385
|
+
created: status.created,
|
|
14386
|
+
deleted: status.deleted,
|
|
14387
|
+
staged,
|
|
14388
|
+
renamed: status.renamed || []
|
|
14389
|
+
};
|
|
14390
|
+
} catch (e) {
|
|
14391
|
+
throw errors_createGitError.commandFailed("status", e.message);
|
|
14392
|
+
}
|
|
14505
14393
|
}
|
|
14506
|
-
|
|
14507
|
-
|
|
14508
|
-
|
|
14509
|
-
|
|
14510
|
-
|
|
14511
|
-
|
|
14512
|
-
|
|
14513
|
-
|
|
14514
|
-
|
|
14515
|
-
|
|
14516
|
-
|
|
14517
|
-
|
|
14518
|
-
|
|
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 [];
|
|
14394
|
+
async discardModeOnlyChanges(paths) {
|
|
14395
|
+
const discarded = [];
|
|
14396
|
+
for (const relativePath of paths)try {
|
|
14397
|
+
const headMode = await this.getHeadFileMode(relativePath);
|
|
14398
|
+
if ("100644" !== headMode && "100755" !== headMode) continue;
|
|
14399
|
+
const contentUnchanged = await this.hasSameContentAsHead(relativePath);
|
|
14400
|
+
if (!contentUnchanged) continue;
|
|
14401
|
+
await this.restoreExecutableBit(relativePath, "100755" === headMode);
|
|
14402
|
+
discarded.push(relativePath);
|
|
14403
|
+
} catch (e) {
|
|
14404
|
+
throw errors_createGitError.commandFailed("discard mode-only changes", e.message);
|
|
14405
|
+
}
|
|
14406
|
+
return discarded;
|
|
14547
14407
|
}
|
|
14548
|
-
|
|
14549
|
-
|
|
14550
|
-
|
|
14551
|
-
|
|
14552
|
-
|
|
14553
|
-
|
|
14554
|
-
|
|
14555
|
-
|
|
14556
|
-
|
|
14557
|
-
|
|
14558
|
-
|
|
14559
|
-
|
|
14560
|
-
|
|
14561
|
-
|
|
14562
|
-
|
|
14563
|
-
|
|
14564
|
-
|
|
14565
|
-
|
|
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);
|
|
14408
|
+
async discardStagedModeOnlyChanges(paths) {
|
|
14409
|
+
const discarded = [];
|
|
14410
|
+
for (const relativePath of paths)try {
|
|
14411
|
+
const headMode = await this.getHeadFileMode(relativePath);
|
|
14412
|
+
if ("100644" !== headMode && "100755" !== headMode) continue;
|
|
14413
|
+
const indexContentUnchanged = await this.hasSameIndexContentAsHead(relativePath);
|
|
14414
|
+
if (!indexContentUnchanged) continue;
|
|
14415
|
+
await this.git.raw([
|
|
14416
|
+
"reset",
|
|
14417
|
+
"-q",
|
|
14418
|
+
"HEAD",
|
|
14419
|
+
"--",
|
|
14420
|
+
relativePath
|
|
14421
|
+
]);
|
|
14422
|
+
await this.restoreExecutableBit(relativePath, "100755" === headMode);
|
|
14423
|
+
discarded.push(relativePath);
|
|
14424
|
+
} catch (e) {
|
|
14425
|
+
throw errors_createGitError.commandFailed("discard staged mode-only changes", e.message);
|
|
14608
14426
|
}
|
|
14427
|
+
return discarded;
|
|
14609
14428
|
}
|
|
14610
|
-
|
|
14611
|
-
const
|
|
14612
|
-
|
|
14613
|
-
|
|
14614
|
-
|
|
14615
|
-
|
|
14429
|
+
async getHeadFileMode(relativePath) {
|
|
14430
|
+
const output = await this.git.raw([
|
|
14431
|
+
"ls-tree",
|
|
14432
|
+
"HEAD",
|
|
14433
|
+
"--",
|
|
14434
|
+
relativePath
|
|
14435
|
+
]);
|
|
14436
|
+
const match = output.match(/^(\d{6})\s/);
|
|
14437
|
+
return match?.[1] ?? null;
|
|
14438
|
+
}
|
|
14439
|
+
async hasSameContentAsHead(relativePath) {
|
|
14440
|
+
const headHash = (await this.git.revparse([
|
|
14441
|
+
`HEAD:${relativePath}`
|
|
14442
|
+
])).trim();
|
|
14443
|
+
const worktreeHash = (await this.git.raw([
|
|
14444
|
+
"hash-object",
|
|
14445
|
+
"--",
|
|
14446
|
+
relativePath
|
|
14447
|
+
])).trim();
|
|
14448
|
+
return headHash === worktreeHash;
|
|
14449
|
+
}
|
|
14450
|
+
async hasSameIndexContentAsHead(relativePath) {
|
|
14451
|
+
const headHash = (await this.git.revparse([
|
|
14452
|
+
`HEAD:${relativePath}`
|
|
14453
|
+
])).trim();
|
|
14454
|
+
const indexHash = (await this.git.revparse([
|
|
14455
|
+
`:${relativePath}`
|
|
14456
|
+
])).trim();
|
|
14457
|
+
return headHash === indexHash;
|
|
14458
|
+
}
|
|
14459
|
+
async restoreExecutableBit(relativePath, executable) {
|
|
14460
|
+
const filePath = external_path_default().join(this.repoPath, relativePath);
|
|
14461
|
+
const stat = await external_fs_.promises.stat(filePath);
|
|
14462
|
+
const mode = executable ? 73 | stat.mode : -74 & stat.mode;
|
|
14463
|
+
if ((511 & stat.mode) !== (511 & mode)) await external_fs_.promises.chmod(filePath, mode);
|
|
14464
|
+
}
|
|
14465
|
+
async hasUncommittedChanges() {
|
|
14466
|
+
const status = await this.getStatus();
|
|
14467
|
+
return !status.isClean;
|
|
14468
|
+
}
|
|
14469
|
+
async fetch(url, refSpec) {
|
|
14470
|
+
let attempt = 0;
|
|
14471
|
+
while(true)try {
|
|
14472
|
+
await this.git.fetch([
|
|
14473
|
+
url,
|
|
14474
|
+
refSpec
|
|
14475
|
+
]);
|
|
14476
|
+
if (attempt > 0) this.emit("fetch-retry-resolved", {
|
|
14477
|
+
attempts: attempt,
|
|
14478
|
+
outcome: "succeeded"
|
|
14616
14479
|
});
|
|
14617
|
-
|
|
14618
|
-
|
|
14619
|
-
|
|
14620
|
-
|
|
14621
|
-
|
|
14622
|
-
|
|
14480
|
+
return;
|
|
14481
|
+
} catch (e) {
|
|
14482
|
+
const err = e;
|
|
14483
|
+
if (!isWantNotValidError(err)) {
|
|
14484
|
+
if (attempt > 0) this.emit("fetch-retry-resolved", {
|
|
14485
|
+
attempts: attempt,
|
|
14486
|
+
outcome: "failed"
|
|
14487
|
+
});
|
|
14488
|
+
throw errors_createGitError.fetchFailed(err.message);
|
|
14489
|
+
}
|
|
14490
|
+
attempt++;
|
|
14491
|
+
this.emit("fetch-retry", {
|
|
14492
|
+
attempt,
|
|
14493
|
+
delayMs: FETCH_RETRY_DELAY_MS,
|
|
14494
|
+
error: err.message
|
|
14623
14495
|
});
|
|
14624
|
-
|
|
14625
|
-
await
|
|
14496
|
+
logger_logger.verbose(`git fetch race (attempt ${attempt}, sleeping ${FETCH_RETRY_DELAY_MS}ms): ${err.message}`);
|
|
14497
|
+
await (0, promises_namespaceObject.setTimeout)(FETCH_RETRY_DELAY_MS);
|
|
14626
14498
|
}
|
|
14627
14499
|
}
|
|
14628
|
-
|
|
14629
|
-
|
|
14630
|
-
|
|
14631
|
-
|
|
14632
|
-
|
|
14633
|
-
|
|
14634
|
-
|
|
14635
|
-
|
|
14636
|
-
|
|
14637
|
-
|
|
14638
|
-
|
|
14639
|
-
|
|
14640
|
-
await
|
|
14500
|
+
async reset(ref, mode = "mixed") {
|
|
14501
|
+
await this.runGitCommandWithIndexLockRetry("reset", ()=>this.git.reset([
|
|
14502
|
+
`--${mode}`,
|
|
14503
|
+
ref
|
|
14504
|
+
]));
|
|
14505
|
+
}
|
|
14506
|
+
async checkout(paths) {
|
|
14507
|
+
await this.runGitCommandWithIndexLockRetry("checkout", ()=>this.git.checkout(paths));
|
|
14508
|
+
}
|
|
14509
|
+
async runGitCommandWithIndexLockRetry(command, operation) {
|
|
14510
|
+
let lastError;
|
|
14511
|
+
for(let attempt = 0; attempt <= git_GitService.INDEX_LOCK_RETRY_DELAYS_MS.length; attempt += 1)try {
|
|
14512
|
+
await operation();
|
|
14513
|
+
return;
|
|
14514
|
+
} catch (e) {
|
|
14515
|
+
lastError = e;
|
|
14516
|
+
if (!this.isIndexLockError(e) || attempt === git_GitService.INDEX_LOCK_RETRY_DELAYS_MS.length) throw errors_createGitError.commandFailed(command, e.message);
|
|
14517
|
+
await (0, promises_namespaceObject.setTimeout)(git_GitService.INDEX_LOCK_RETRY_DELAYS_MS[attempt]);
|
|
14641
14518
|
}
|
|
14519
|
+
throw errors_createGitError.commandFailed(command, lastError.message);
|
|
14642
14520
|
}
|
|
14643
|
-
|
|
14644
|
-
const
|
|
14645
|
-
|
|
14646
|
-
recursive: true
|
|
14647
|
-
});
|
|
14648
|
-
await promises_default().writeFile(targetPath, Buffer.from(asset.content, "base64"));
|
|
14521
|
+
isIndexLockError(error) {
|
|
14522
|
+
const message = error.message ?? "";
|
|
14523
|
+
return message.includes("Unable to create") && message.includes("index.lock") && message.includes("File exists");
|
|
14649
14524
|
}
|
|
14650
|
-
|
|
14651
|
-
|
|
14652
|
-
|
|
14653
|
-
|
|
14654
|
-
|
|
14655
|
-
|
|
14525
|
+
async stash(message) {
|
|
14526
|
+
try {
|
|
14527
|
+
const args = [
|
|
14528
|
+
"stash",
|
|
14529
|
+
"push",
|
|
14530
|
+
"--include-untracked"
|
|
14531
|
+
];
|
|
14532
|
+
if (message) args.push("-m", message);
|
|
14533
|
+
const result = await this.git.raw(args);
|
|
14534
|
+
return !result.includes("No local changes to save");
|
|
14535
|
+
} catch (e) {
|
|
14536
|
+
throw errors_createGitError.commandFailed("stash", e.message);
|
|
14537
|
+
}
|
|
14656
14538
|
}
|
|
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);
|
|
14539
|
+
async stashPop() {
|
|
14540
|
+
try {
|
|
14541
|
+
await this.git.raw([
|
|
14542
|
+
"stash",
|
|
14543
|
+
"pop"
|
|
14544
|
+
]);
|
|
14545
|
+
} catch (e) {
|
|
14546
|
+
throw errors_createGitError.commandFailed("stash pop", e.message);
|
|
14547
|
+
}
|
|
14722
14548
|
}
|
|
14723
|
-
|
|
14724
|
-
|
|
14549
|
+
async clean(files) {
|
|
14550
|
+
try {
|
|
14551
|
+
await this.git.clean(CleanOptions.FORCE, files);
|
|
14552
|
+
} catch (e) {
|
|
14553
|
+
throw errors_createGitError.commandFailed("clean", e.message);
|
|
14554
|
+
}
|
|
14725
14555
|
}
|
|
14726
|
-
|
|
14727
|
-
|
|
14556
|
+
async diffNames(fromCommit, toCommit) {
|
|
14557
|
+
try {
|
|
14558
|
+
const diffResult = await this.git.diff([
|
|
14559
|
+
fromCommit,
|
|
14560
|
+
toCommit,
|
|
14561
|
+
"--name-only"
|
|
14562
|
+
]);
|
|
14563
|
+
const files = diffResult.split("\n").filter((f)=>f.trim());
|
|
14564
|
+
return files;
|
|
14565
|
+
} catch (e) {
|
|
14566
|
+
throw errors_createGitError.commandFailed("diff", e.message);
|
|
14567
|
+
}
|
|
14728
14568
|
}
|
|
14729
|
-
async
|
|
14569
|
+
async getAheadBehind(localRef, remoteRef) {
|
|
14730
14570
|
try {
|
|
14731
|
-
const
|
|
14732
|
-
"
|
|
14733
|
-
|
|
14734
|
-
|
|
14735
|
-
|
|
14571
|
+
const result = await this.git.raw([
|
|
14572
|
+
"rev-list",
|
|
14573
|
+
"--left-right",
|
|
14574
|
+
"--count",
|
|
14575
|
+
`${remoteRef}...${localRef}`
|
|
14576
|
+
]);
|
|
14577
|
+
const [behind, ahead] = result.trim().split("\t").map(Number);
|
|
14578
|
+
return {
|
|
14579
|
+
ahead,
|
|
14580
|
+
behind
|
|
14581
|
+
};
|
|
14582
|
+
} catch (e) {
|
|
14583
|
+
throw errors_createGitError.commandFailed("rev-list", e.message);
|
|
14584
|
+
}
|
|
14585
|
+
}
|
|
14586
|
+
async show(refPath) {
|
|
14587
|
+
try {
|
|
14588
|
+
const content = await this.git.show([
|
|
14589
|
+
refPath
|
|
14590
|
+
]);
|
|
14591
|
+
return content;
|
|
14592
|
+
} catch (e) {
|
|
14593
|
+
throw errors_createGitError.commandFailed("show", e.message);
|
|
14594
|
+
}
|
|
14595
|
+
}
|
|
14596
|
+
async push(url, refSpec, force = false) {
|
|
14597
|
+
try {
|
|
14598
|
+
const args = force ? [
|
|
14599
|
+
"push",
|
|
14600
|
+
"--force",
|
|
14601
|
+
url,
|
|
14602
|
+
refSpec
|
|
14603
|
+
] : [
|
|
14604
|
+
"push",
|
|
14605
|
+
url,
|
|
14606
|
+
refSpec
|
|
14607
|
+
];
|
|
14608
|
+
await this.git.raw(args);
|
|
14736
14609
|
} catch (e) {
|
|
14737
|
-
throw errors_createGitError.commandFailed("
|
|
14610
|
+
throw errors_createGitError.commandFailed("push", e.message);
|
|
14738
14611
|
}
|
|
14739
14612
|
}
|
|
14740
|
-
async
|
|
14613
|
+
async rebase(onto) {
|
|
14741
14614
|
try {
|
|
14742
|
-
|
|
14743
|
-
"
|
|
14744
|
-
|
|
14615
|
+
await this.git.raw([
|
|
14616
|
+
"rebase",
|
|
14617
|
+
onto
|
|
14745
14618
|
]);
|
|
14746
|
-
if ("HEAD" === branchRef) throw createSyncError.detachedHead();
|
|
14747
|
-
return branchRef;
|
|
14748
14619
|
} catch (e) {
|
|
14749
|
-
|
|
14750
|
-
throw createSyncError.detachedHead();
|
|
14620
|
+
throw errors_createGitError.commandFailed("rebase", e.message);
|
|
14751
14621
|
}
|
|
14752
14622
|
}
|
|
14753
|
-
async
|
|
14623
|
+
async rebaseAbort() {
|
|
14754
14624
|
try {
|
|
14755
|
-
|
|
14756
|
-
"
|
|
14757
|
-
|
|
14758
|
-
|
|
14625
|
+
await this.git.raw([
|
|
14626
|
+
"rebase",
|
|
14627
|
+
"--abort"
|
|
14628
|
+
]);
|
|
14759
14629
|
} catch (e) {
|
|
14760
|
-
throw errors_createGitError.commandFailed("
|
|
14630
|
+
throw errors_createGitError.commandFailed("rebase --abort", e.message);
|
|
14761
14631
|
}
|
|
14762
14632
|
}
|
|
14763
|
-
async
|
|
14633
|
+
async isAncestor(ancestorRef, descendantRef) {
|
|
14764
14634
|
try {
|
|
14765
|
-
const
|
|
14766
|
-
"
|
|
14635
|
+
const mergeBase = (await this.git.raw([
|
|
14636
|
+
"merge-base",
|
|
14637
|
+
ancestorRef,
|
|
14638
|
+
descendantRef
|
|
14767
14639
|
])).trim();
|
|
14768
|
-
const
|
|
14769
|
-
|
|
14770
|
-
"-1",
|
|
14771
|
-
"--format=%s"
|
|
14640
|
+
const ancestorCommit = (await this.git.revparse([
|
|
14641
|
+
ancestorRef
|
|
14772
14642
|
])).trim();
|
|
14773
|
-
return
|
|
14774
|
-
|
|
14775
|
-
|
|
14776
|
-
message
|
|
14777
|
-
};
|
|
14778
|
-
} catch (e) {
|
|
14779
|
-
throw errors_createGitError.commandFailed("log", e.message);
|
|
14643
|
+
return mergeBase === ancestorCommit;
|
|
14644
|
+
} catch {
|
|
14645
|
+
return false;
|
|
14780
14646
|
}
|
|
14781
14647
|
}
|
|
14782
|
-
async
|
|
14648
|
+
async mergeFastForward(ref) {
|
|
14649
|
+
await this.runGitCommandWithIndexLockRetry("merge --ff-only", ()=>this.git.raw([
|
|
14650
|
+
"merge",
|
|
14651
|
+
"--ff-only",
|
|
14652
|
+
ref
|
|
14653
|
+
]));
|
|
14654
|
+
}
|
|
14655
|
+
async deleteRef(ref) {
|
|
14783
14656
|
try {
|
|
14784
|
-
|
|
14785
|
-
|
|
14786
|
-
|
|
14787
|
-
|
|
14788
|
-
|
|
14789
|
-
|
|
14790
|
-
|
|
14791
|
-
|
|
14792
|
-
|
|
14793
|
-
|
|
14794
|
-
|
|
14795
|
-
|
|
14796
|
-
|
|
14797
|
-
|
|
14657
|
+
await this.git.raw([
|
|
14658
|
+
"update-ref",
|
|
14659
|
+
"-d",
|
|
14660
|
+
ref
|
|
14661
|
+
]);
|
|
14662
|
+
} catch (e) {}
|
|
14663
|
+
}
|
|
14664
|
+
async getRemotes() {
|
|
14665
|
+
try {
|
|
14666
|
+
const remotes = await this.git.getRemotes(true);
|
|
14667
|
+
return remotes.map((r)=>({
|
|
14668
|
+
name: r.name,
|
|
14669
|
+
fetchUrl: r.refs.fetch
|
|
14670
|
+
}));
|
|
14798
14671
|
} catch (e) {
|
|
14799
|
-
throw errors_createGitError.commandFailed("
|
|
14672
|
+
throw errors_createGitError.commandFailed("remote", e.message);
|
|
14800
14673
|
}
|
|
14801
14674
|
}
|
|
14802
|
-
async
|
|
14803
|
-
const
|
|
14804
|
-
|
|
14805
|
-
|
|
14806
|
-
|
|
14807
|
-
|
|
14808
|
-
|
|
14809
|
-
|
|
14810
|
-
|
|
14811
|
-
|
|
14812
|
-
|
|
14675
|
+
async isGitInitialized() {
|
|
14676
|
+
const gitPath = external_path_default().join(this.repoPath, ".git");
|
|
14677
|
+
return external_fs_.existsSync(gitPath);
|
|
14678
|
+
}
|
|
14679
|
+
async removeEmptyDirectories(removedFiles) {
|
|
14680
|
+
const directoriesToCheck = new Set();
|
|
14681
|
+
for (const file of removedFiles){
|
|
14682
|
+
let dir = external_path_default().dirname(file);
|
|
14683
|
+
while(dir && "." !== dir){
|
|
14684
|
+
directoriesToCheck.add(dir);
|
|
14685
|
+
const parentDir = external_path_default().dirname(dir);
|
|
14686
|
+
if (parentDir === dir) break;
|
|
14687
|
+
dir = parentDir;
|
|
14688
|
+
}
|
|
14813
14689
|
}
|
|
14814
|
-
|
|
14690
|
+
const sortedDirs = Array.from(directoriesToCheck).sort((a, b)=>b.split("/").length - a.split("/").length);
|
|
14691
|
+
for (const dir of sortedDirs)try {
|
|
14692
|
+
const dirPath = external_path_default().join(this.repoPath, dir);
|
|
14693
|
+
if (!external_fs_.existsSync(dirPath)) continue;
|
|
14694
|
+
const entries = await external_fs_.promises.readdir(dirPath);
|
|
14695
|
+
if (0 === entries.length) await external_fs_.promises.rmdir(dirPath);
|
|
14696
|
+
} catch (error) {}
|
|
14815
14697
|
}
|
|
14816
|
-
|
|
14817
|
-
|
|
14818
|
-
|
|
14819
|
-
|
|
14820
|
-
|
|
14821
|
-
|
|
14822
|
-
|
|
14823
|
-
|
|
14824
|
-
|
|
14825
|
-
|
|
14826
|
-
|
|
14827
|
-
|
|
14828
|
-
|
|
14829
|
-
|
|
14830
|
-
|
|
14831
|
-
discarded.push(relativePath);
|
|
14832
|
-
} catch (e) {
|
|
14833
|
-
throw errors_createGitError.commandFailed("discard staged mode-only changes", e.message);
|
|
14698
|
+
}
|
|
14699
|
+
async function getStagedFileChanges(git, gitService) {
|
|
14700
|
+
try {
|
|
14701
|
+
const status = await git.status();
|
|
14702
|
+
const renames = status.renamed || [];
|
|
14703
|
+
const stagedFiles = status.files.filter((f)=>" " !== f.index && "?" !== f.index);
|
|
14704
|
+
const stagedModeOnlyPaths = new Set(gitService ? await gitService.discardStagedModeOnlyChanges(stagedFiles.filter((f)=>"R" !== f.index && "D" !== f.index).map((f)=>f.path)) : []);
|
|
14705
|
+
const stagedRenames = [];
|
|
14706
|
+
for (const f of stagedFiles)if ("R" === f.index) {
|
|
14707
|
+
const rename = renames.find((r)=>r.to === f.path);
|
|
14708
|
+
if (rename) stagedRenames.push({
|
|
14709
|
+
path: rename.to,
|
|
14710
|
+
type: "rename",
|
|
14711
|
+
from: rename.from
|
|
14712
|
+
});
|
|
14834
14713
|
}
|
|
14835
|
-
|
|
14714
|
+
const stagedRenamedFromPaths = new Set(stagedRenames.map((r)=>r.from));
|
|
14715
|
+
const stagedRenamedToPaths = new Set(stagedRenames.map((r)=>r.path));
|
|
14716
|
+
const changes = [];
|
|
14717
|
+
for (const f of stagedFiles){
|
|
14718
|
+
if ("R" !== f.index) {
|
|
14719
|
+
if (!stagedModeOnlyPaths.has(f.path)) {
|
|
14720
|
+
if (!(stagedRenamedFromPaths.has(f.path) || stagedRenamedToPaths.has(f.path))) if ("D" === f.index) changes.push({
|
|
14721
|
+
path: f.path,
|
|
14722
|
+
type: "unlink"
|
|
14723
|
+
});
|
|
14724
|
+
else if ("A" === f.index || "?" === f.index) changes.push({
|
|
14725
|
+
path: f.path,
|
|
14726
|
+
type: "add"
|
|
14727
|
+
});
|
|
14728
|
+
else changes.push({
|
|
14729
|
+
path: f.path,
|
|
14730
|
+
type: "change"
|
|
14731
|
+
});
|
|
14732
|
+
}
|
|
14733
|
+
}
|
|
14734
|
+
}
|
|
14735
|
+
changes.push(...stagedRenames);
|
|
14736
|
+
return changes;
|
|
14737
|
+
} catch (e) {
|
|
14738
|
+
throw errors_createGitError.commandFailed("status", e.message);
|
|
14836
14739
|
}
|
|
14837
|
-
|
|
14838
|
-
|
|
14839
|
-
|
|
14840
|
-
|
|
14841
|
-
|
|
14842
|
-
|
|
14843
|
-
|
|
14844
|
-
|
|
14845
|
-
|
|
14740
|
+
}
|
|
14741
|
+
async function git_getCurrentOrFallbackBranchName(git) {
|
|
14742
|
+
const branchRef = (await git.revparse([
|
|
14743
|
+
"--abbrev-ref",
|
|
14744
|
+
"HEAD"
|
|
14745
|
+
])).trim();
|
|
14746
|
+
if ("HEAD" !== branchRef) return branchRef;
|
|
14747
|
+
const [localBranches, remoteBranches] = await Promise.all([
|
|
14748
|
+
git.raw([
|
|
14749
|
+
"branch",
|
|
14750
|
+
"--format=%(refname:short)",
|
|
14751
|
+
"--contains",
|
|
14752
|
+
"HEAD"
|
|
14753
|
+
]),
|
|
14754
|
+
git.raw([
|
|
14755
|
+
"branch",
|
|
14756
|
+
"-r",
|
|
14757
|
+
"--format=%(refname:short)",
|
|
14758
|
+
"--contains",
|
|
14759
|
+
"HEAD"
|
|
14760
|
+
])
|
|
14761
|
+
]);
|
|
14762
|
+
const branchNames = [
|
|
14763
|
+
...parseBranchList(localBranches),
|
|
14764
|
+
...parseBranchList(remoteBranches).filter((branchName)=>!branchName.endsWith("/HEAD")).map((branchName)=>branchName.replace(/^[^/]+\//, ""))
|
|
14765
|
+
];
|
|
14766
|
+
const branchSet = new Set(branchNames);
|
|
14767
|
+
if (branchSet.has("master")) return "master";
|
|
14768
|
+
if (branchSet.has("main")) return "main";
|
|
14769
|
+
return "master";
|
|
14770
|
+
}
|
|
14771
|
+
function parseBranchList(output) {
|
|
14772
|
+
return output.split(/\r?\n/).map((line)=>line.trim()).filter(Boolean);
|
|
14773
|
+
}
|
|
14774
|
+
function anvil_api_getDefaultAnvilUrl() {
|
|
14775
|
+
return resolveAnvilUrl();
|
|
14776
|
+
}
|
|
14777
|
+
async function anvil_api_validateAppId(appId, anvilUrl = anvil_api_getDefaultAnvilUrl(), username) {
|
|
14778
|
+
const authToken = await auth_getValidAuthToken(anvilUrl, username);
|
|
14779
|
+
try {
|
|
14780
|
+
const resp = await fetch(`${anvilUrl}/ide/api/_/apps/validate-app-id`, {
|
|
14781
|
+
method: "POST",
|
|
14782
|
+
headers: {
|
|
14783
|
+
Authorization: `Bearer ${authToken}`,
|
|
14784
|
+
"Content-Type": "application/json"
|
|
14785
|
+
},
|
|
14786
|
+
body: JSON.stringify({
|
|
14787
|
+
app_id: appId
|
|
14788
|
+
})
|
|
14789
|
+
});
|
|
14790
|
+
const data = await resp.json();
|
|
14791
|
+
if (resp.ok) return {
|
|
14792
|
+
valid: data.valid ?? false,
|
|
14793
|
+
app_name: data.app_name
|
|
14794
|
+
};
|
|
14795
|
+
if (401 === resp.status) throw createAuthError.invalid("Authentication failed");
|
|
14796
|
+
if (403 === resp.status) throw createAppError.accessDenied(appId);
|
|
14797
|
+
if (404 === resp.status) throw createAppError.notFound(appId);
|
|
14798
|
+
logger_logger.debug(`validate-app-id failed: ${resp.status} ${resp.statusText}`);
|
|
14799
|
+
return {
|
|
14800
|
+
valid: false,
|
|
14801
|
+
error: data.error || `Server error: ${resp.status}`
|
|
14802
|
+
};
|
|
14803
|
+
} catch (error) {
|
|
14804
|
+
if (error.type) throw error;
|
|
14805
|
+
throw createNetworkError.network(error.message);
|
|
14806
|
+
}
|
|
14807
|
+
}
|
|
14808
|
+
async function lookupByCommit(commitId, branchName, anvilUrl = anvil_api_getDefaultAnvilUrl(), username) {
|
|
14809
|
+
const authToken = await auth_getValidAuthToken(anvilUrl, username);
|
|
14810
|
+
try {
|
|
14811
|
+
const resp = await fetch(`${anvilUrl}/ide/api/_/apps/lookup-by-commit`, {
|
|
14812
|
+
method: "POST",
|
|
14813
|
+
headers: {
|
|
14814
|
+
Authorization: `Bearer ${authToken}`,
|
|
14815
|
+
"Content-Type": "application/json"
|
|
14816
|
+
},
|
|
14817
|
+
body: JSON.stringify({
|
|
14818
|
+
commit_id: commitId,
|
|
14819
|
+
branch_name: branchName
|
|
14820
|
+
})
|
|
14821
|
+
});
|
|
14822
|
+
if (!resp.ok) {
|
|
14823
|
+
if (401 === resp.status) throw createAuthError.invalid("Authentication failed");
|
|
14824
|
+
throw createNetworkError.server(resp.status, resp.statusText);
|
|
14825
|
+
}
|
|
14826
|
+
const data = await resp.json();
|
|
14827
|
+
return data;
|
|
14828
|
+
} catch (error) {
|
|
14829
|
+
if (error.type) throw error;
|
|
14830
|
+
throw createNetworkError.network(error.message);
|
|
14846
14831
|
}
|
|
14847
|
-
|
|
14848
|
-
|
|
14849
|
-
|
|
14850
|
-
|
|
14851
|
-
|
|
14852
|
-
|
|
14853
|
-
|
|
14854
|
-
|
|
14855
|
-
|
|
14856
|
-
|
|
14832
|
+
}
|
|
14833
|
+
async function listAppsForCheckout(options = {}) {
|
|
14834
|
+
const anvilUrl = options.anvilUrl ?? anvil_api_getDefaultAnvilUrl();
|
|
14835
|
+
const authToken = await auth_getValidAuthToken(anvilUrl, options.username);
|
|
14836
|
+
const params = new URLSearchParams();
|
|
14837
|
+
if ("number" == typeof options.limit) params.set("limit", String(options.limit));
|
|
14838
|
+
if (options.cursor) params.set("cursor", options.cursor);
|
|
14839
|
+
if (options.q && options.q.trim()) params.set("q", options.q.trim());
|
|
14840
|
+
const query = params.toString();
|
|
14841
|
+
const url = `${anvilUrl}/ide/api/_/apps${query ? `?${query}` : ""}`;
|
|
14842
|
+
try {
|
|
14843
|
+
const resp = await fetch(url, {
|
|
14844
|
+
method: "GET",
|
|
14845
|
+
headers: {
|
|
14846
|
+
Authorization: `Bearer ${authToken}`
|
|
14847
|
+
},
|
|
14848
|
+
signal: options.signal
|
|
14849
|
+
});
|
|
14850
|
+
if (!resp.ok) {
|
|
14851
|
+
if (401 === resp.status) throw createAuthError.invalid("Authentication failed");
|
|
14852
|
+
throw createNetworkError.server(resp.status, resp.statusText);
|
|
14853
|
+
}
|
|
14854
|
+
const data = await resp.json();
|
|
14855
|
+
return {
|
|
14856
|
+
apps: Array.isArray(data.apps) ? data.apps : [],
|
|
14857
|
+
next_cursor: "string" == typeof data.next_cursor ? data.next_cursor : null
|
|
14858
|
+
};
|
|
14859
|
+
} catch (error) {
|
|
14860
|
+
if (error.type) throw error;
|
|
14861
|
+
throw createNetworkError.network(error.message);
|
|
14857
14862
|
}
|
|
14858
|
-
|
|
14859
|
-
|
|
14860
|
-
|
|
14861
|
-
|
|
14862
|
-
|
|
14863
|
-
|
|
14864
|
-
|
|
14865
|
-
|
|
14863
|
+
}
|
|
14864
|
+
async function saveUpdates(appId, branchName, payload, anvilUrl = anvil_api_getDefaultAnvilUrl(), authToken) {
|
|
14865
|
+
try {
|
|
14866
|
+
const resp = await fetch(`${anvilUrl}/ide/api/_/apps/${appId}/update?make_fresh_version=false&branch=${branchName}`, {
|
|
14867
|
+
method: "PUT",
|
|
14868
|
+
headers: {
|
|
14869
|
+
Authorization: `Bearer ${authToken}`,
|
|
14870
|
+
"Content-Type": "application/json"
|
|
14871
|
+
},
|
|
14872
|
+
body: JSON.stringify(payload)
|
|
14873
|
+
});
|
|
14874
|
+
const data = await resp.json();
|
|
14875
|
+
if (401 === resp.status) throw createAuthError.invalid(`Authentication failed (401): ${data.error || "unauthorized"}`);
|
|
14876
|
+
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)`);
|
|
14877
|
+
return {
|
|
14878
|
+
version: data.version,
|
|
14879
|
+
overtaken: data.overtaken,
|
|
14880
|
+
latest_version: data.latest_version,
|
|
14881
|
+
error: 200 !== resp.status ? data.error || `Status ${resp.status}` : void 0
|
|
14882
|
+
};
|
|
14883
|
+
} catch (error) {
|
|
14884
|
+
if (error.type) throw error;
|
|
14885
|
+
throw createNetworkError.network(error.message);
|
|
14866
14886
|
}
|
|
14867
|
-
|
|
14868
|
-
|
|
14869
|
-
|
|
14870
|
-
|
|
14871
|
-
|
|
14887
|
+
}
|
|
14888
|
+
function anvil_api_getGitFetchUrl(appId, authToken, gitUrl = anvil_api_getDefaultAnvilUrl()) {
|
|
14889
|
+
const url = new URL(gitUrl);
|
|
14890
|
+
const encodedToken = encodeURIComponent(authToken);
|
|
14891
|
+
return `${url.protocol}//git:${encodedToken}@${url.hostname}${url.port ? ":" + url.port : ""}/git/${appId}.git?no_freeze=true&q=`;
|
|
14892
|
+
}
|
|
14893
|
+
function anvil_api_getGitPushUrl(appId, authToken, anvilUrl = anvil_api_getDefaultAnvilUrl()) {
|
|
14894
|
+
const url = new URL(anvilUrl);
|
|
14895
|
+
const encodedToken = encodeURIComponent(authToken);
|
|
14896
|
+
return `${url.protocol}//git:${encodedToken}@${url.hostname}${url.port ? ":" + url.port : ""}/git/${appId}.git`;
|
|
14897
|
+
}
|
|
14898
|
+
function getWebSocketUrl(appId, authToken, anvilUrl = anvil_api_getDefaultAnvilUrl()) {
|
|
14899
|
+
return anvilUrl.replace(/^http/, "ws") + `/ide/api/_/apps/${appId}/ws?access_token=${authToken}`;
|
|
14900
|
+
}
|
|
14901
|
+
async function getLatestVersion() {
|
|
14902
|
+
try {
|
|
14903
|
+
const response = await fetch("https://registry.npmjs.org/@anvil-works/anvil-cli/latest");
|
|
14904
|
+
if (!response.ok) return null;
|
|
14905
|
+
const data = await response.json();
|
|
14906
|
+
return data.version;
|
|
14907
|
+
} catch (e) {
|
|
14908
|
+
return null;
|
|
14872
14909
|
}
|
|
14873
|
-
|
|
14874
|
-
|
|
14875
|
-
|
|
14910
|
+
}
|
|
14911
|
+
function anvil_api_filterCandidates(candidates, explicitUrl, explicitUsername) {
|
|
14912
|
+
let filtered = candidates;
|
|
14913
|
+
if (explicitUrl) {
|
|
14914
|
+
const normalizedExplicit = config_normalizeAnvilUrl(explicitUrl);
|
|
14915
|
+
filtered = filtered.filter((c)=>c.detectedUrl && config_normalizeAnvilUrl(c.detectedUrl) === normalizedExplicit);
|
|
14876
14916
|
}
|
|
14877
|
-
|
|
14878
|
-
|
|
14879
|
-
|
|
14880
|
-
|
|
14881
|
-
|
|
14882
|
-
|
|
14883
|
-
|
|
14884
|
-
|
|
14885
|
-
|
|
14886
|
-
|
|
14887
|
-
|
|
14888
|
-
|
|
14889
|
-
|
|
14890
|
-
|
|
14891
|
-
|
|
14892
|
-
|
|
14893
|
-
|
|
14894
|
-
|
|
14917
|
+
if (explicitUsername) filtered = filtered.filter((c)=>!c.detectedUsername || c.detectedUsername === explicitUsername);
|
|
14918
|
+
return filtered;
|
|
14919
|
+
}
|
|
14920
|
+
function anvil_api_formatCandidateLabel(candidate) {
|
|
14921
|
+
const parts = [
|
|
14922
|
+
candidate.appId
|
|
14923
|
+
];
|
|
14924
|
+
if (candidate.detectedUrl) if (candidate.detectedUsername) parts.push(`(${candidate.detectedUsername} on ${candidate.detectedUrl})`);
|
|
14925
|
+
else parts.push(`(${candidate.detectedUrl})`);
|
|
14926
|
+
parts.push(`- ${candidate.description}`);
|
|
14927
|
+
return parts.join(" ");
|
|
14928
|
+
}
|
|
14929
|
+
function anvil_api_lookupRemoteInfoForAppId(appId, detectedRemotes) {
|
|
14930
|
+
const matches = detectedRemotes.filter((c)=>c.appId === appId);
|
|
14931
|
+
if (0 === matches.length) return {};
|
|
14932
|
+
const withUsername = matches.find((c)=>c.detectedUsername);
|
|
14933
|
+
if (withUsername) return {
|
|
14934
|
+
detectedUrl: withUsername.detectedUrl,
|
|
14935
|
+
detectedUsername: withUsername.detectedUsername
|
|
14936
|
+
};
|
|
14937
|
+
return {
|
|
14938
|
+
detectedUrl: matches[0].detectedUrl,
|
|
14939
|
+
detectedUsername: matches[0].detectedUsername
|
|
14940
|
+
};
|
|
14941
|
+
}
|
|
14942
|
+
async function anvil_api_detectAppIdsFromAllRemotes(repoPath) {
|
|
14943
|
+
const git = esm_default(repoPath);
|
|
14944
|
+
const out = [];
|
|
14945
|
+
try {
|
|
14946
|
+
const remotes = await git.getRemotes(true);
|
|
14947
|
+
for (const remote of remotes){
|
|
14948
|
+
const httpMatch = remote.refs.fetch?.match(/(?:http|https):\/\/(?:[^@]+@)?([^:\/]+)(?::\d+)?\/git\/([A-Z0-9]+)\.git/);
|
|
14949
|
+
if (httpMatch) {
|
|
14950
|
+
const [, host, detectedAppId] = httpMatch;
|
|
14951
|
+
out.push({
|
|
14952
|
+
appId: detectedAppId,
|
|
14953
|
+
source: "remote",
|
|
14954
|
+
description: `Git remote '${remote.name}'`,
|
|
14955
|
+
detectedUrl: config_normalizeAnvilUrl(host)
|
|
14956
|
+
});
|
|
14957
|
+
continue;
|
|
14958
|
+
}
|
|
14959
|
+
const sshMatch = remote.refs.fetch?.match(/ssh:\/\/([^@]+)@([^:]+):(\d+)\/(?:git\/)?([A-Z0-9]+)\.git/);
|
|
14960
|
+
if (sshMatch) {
|
|
14961
|
+
const [, usernamePart, host, , detectedAppId] = sshMatch;
|
|
14962
|
+
const detectedUsername = usernamePart.includes("%") ? decodeURIComponent(usernamePart) : usernamePart;
|
|
14963
|
+
const finalUsername = "git" !== detectedUsername ? detectedUsername : void 0;
|
|
14964
|
+
out.push({
|
|
14965
|
+
appId: detectedAppId,
|
|
14966
|
+
source: "remote",
|
|
14967
|
+
description: `Git remote '${remote.name}' (SSH)`,
|
|
14968
|
+
detectedUrl: config_normalizeAnvilUrl(host),
|
|
14969
|
+
detectedUsername: finalUsername
|
|
14895
14970
|
});
|
|
14896
|
-
throw errors_createGitError.fetchFailed(err.message);
|
|
14897
14971
|
}
|
|
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
14972
|
}
|
|
14927
|
-
|
|
14928
|
-
|
|
14929
|
-
|
|
14930
|
-
|
|
14931
|
-
|
|
14932
|
-
|
|
14933
|
-
|
|
14934
|
-
|
|
14935
|
-
|
|
14936
|
-
|
|
14937
|
-
|
|
14938
|
-
|
|
14939
|
-
|
|
14940
|
-
|
|
14941
|
-
|
|
14942
|
-
|
|
14943
|
-
|
|
14944
|
-
|
|
14973
|
+
} catch (_e) {}
|
|
14974
|
+
return out;
|
|
14975
|
+
}
|
|
14976
|
+
async function anvil_api_detectAppIdsByCommitLookup(repoPath, options) {
|
|
14977
|
+
const anvilUrl = options.anvilUrl || resolveAnvilUrl();
|
|
14978
|
+
const username = options.username;
|
|
14979
|
+
const git = esm_default(repoPath);
|
|
14980
|
+
const out = [];
|
|
14981
|
+
try {
|
|
14982
|
+
const authToken = await auth_getValidAuthToken(anvilUrl, username);
|
|
14983
|
+
const commitId = (await git.revparse([
|
|
14984
|
+
"HEAD"
|
|
14985
|
+
]))?.trim();
|
|
14986
|
+
if (!commitId) return out;
|
|
14987
|
+
const branchName = await git_getCurrentOrFallbackBranchName(git);
|
|
14988
|
+
const resp = await fetch(`${anvilUrl}/ide/api/_/apps/lookup-by-commit`, {
|
|
14989
|
+
method: "POST",
|
|
14990
|
+
headers: {
|
|
14991
|
+
Authorization: `Bearer ${authToken}`,
|
|
14992
|
+
"Content-Type": "application/json"
|
|
14993
|
+
},
|
|
14994
|
+
body: JSON.stringify({
|
|
14995
|
+
commit_id: commitId,
|
|
14996
|
+
branch_name: branchName
|
|
14997
|
+
})
|
|
14998
|
+
});
|
|
14999
|
+
logger_logger.debug(`Reverse lookup by commit ${commitId} on branch ${branchName} returned ${resp.status}`);
|
|
15000
|
+
if (!resp.ok) {
|
|
15001
|
+
const errorBody = await resp.text();
|
|
15002
|
+
logger_logger.debug(`lookup-by-commit error: ${errorBody}`);
|
|
14945
15003
|
}
|
|
14946
|
-
|
|
14947
|
-
|
|
14948
|
-
|
|
14949
|
-
|
|
14950
|
-
|
|
14951
|
-
|
|
14952
|
-
|
|
14953
|
-
|
|
14954
|
-
|
|
15004
|
+
if (resp.ok) {
|
|
15005
|
+
const data = await resp.json();
|
|
15006
|
+
logger_logger.debug(`data ${JSON.stringify(data)}`);
|
|
15007
|
+
const apps = data?.apps ?? [];
|
|
15008
|
+
for (const app of apps)if (app?.app_id) out.push({
|
|
15009
|
+
appId: app.app_id,
|
|
15010
|
+
source: "remote",
|
|
15011
|
+
description: `Reverse lookup by commit${app.branch ? ` on branch '${app.branch}'` : ""}`
|
|
15012
|
+
});
|
|
14955
15013
|
}
|
|
15014
|
+
} catch (_e) {}
|
|
15015
|
+
return out;
|
|
15016
|
+
}
|
|
15017
|
+
const external_fs_promises_namespaceObject = require("fs/promises");
|
|
15018
|
+
var external_fs_promises_default = /*#__PURE__*/ __webpack_require__.n(external_fs_promises_namespaceObject);
|
|
15019
|
+
function normalizeLineEndings(content) {
|
|
15020
|
+
return content.replace(/\r\n/g, "\n");
|
|
15021
|
+
}
|
|
15022
|
+
function pythonifyName(name) {
|
|
15023
|
+
return name.replace(/[^A-z0-9]/g, "_").replace(/^[0-9]/, "_$&");
|
|
15024
|
+
}
|
|
15025
|
+
function extractPythonName(relativePath, skipParts = 1) {
|
|
15026
|
+
const parts = relativePath.slice(0, -3).split("/");
|
|
15027
|
+
const isPackage = relativePath.endsWith("__init__.py");
|
|
15028
|
+
const relevantParts = isPackage ? parts.slice(skipParts, -1) : parts.slice(skipParts);
|
|
15029
|
+
return relevantParts.map(pythonifyName).join(".");
|
|
15030
|
+
}
|
|
15031
|
+
function deepEqual(a, b) {
|
|
15032
|
+
if (a === b) return true;
|
|
15033
|
+
if (null == a || null == b) return false;
|
|
15034
|
+
if (typeof a !== typeof b) return false;
|
|
15035
|
+
if ("object" != typeof a) return a === b;
|
|
15036
|
+
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
|
15037
|
+
if (Array.isArray(a)) {
|
|
15038
|
+
if (a.length !== b.length) return false;
|
|
15039
|
+
return a.every((item, index)=>deepEqual(item, b[index]));
|
|
14956
15040
|
}
|
|
14957
|
-
|
|
14958
|
-
|
|
14959
|
-
|
|
14960
|
-
|
|
14961
|
-
|
|
14962
|
-
|
|
15041
|
+
const keysA = Object.keys(a);
|
|
15042
|
+
const keysB = Object.keys(b);
|
|
15043
|
+
if (keysA.length !== keysB.length) return false;
|
|
15044
|
+
return keysA.every((key)=>deepEqual(a[key], b[key]));
|
|
15045
|
+
}
|
|
15046
|
+
function parseHtmlWithFrontmatter(htmlContent) {
|
|
15047
|
+
const frontmatterPattern = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
|
|
15048
|
+
const match = htmlContent.match(frontmatterPattern);
|
|
15049
|
+
if (match) {
|
|
15050
|
+
const yamlStr = match[1];
|
|
15051
|
+
const html = match[2];
|
|
15052
|
+
const frontmatter = yamlStr ? external_js_yaml_default().load(yamlStr) ?? {} : {};
|
|
15053
|
+
return {
|
|
15054
|
+
frontmatter,
|
|
15055
|
+
html
|
|
15056
|
+
};
|
|
14963
15057
|
}
|
|
14964
|
-
|
|
14965
|
-
|
|
14966
|
-
|
|
14967
|
-
|
|
14968
|
-
|
|
14969
|
-
|
|
14970
|
-
|
|
14971
|
-
|
|
14972
|
-
|
|
14973
|
-
|
|
14974
|
-
|
|
14975
|
-
|
|
15058
|
+
return {
|
|
15059
|
+
frontmatter: {},
|
|
15060
|
+
html: htmlContent
|
|
15061
|
+
};
|
|
15062
|
+
}
|
|
15063
|
+
function formatHttpError(prefix, status, body) {
|
|
15064
|
+
if (!body) return `${prefix}: ${status}`;
|
|
15065
|
+
try {
|
|
15066
|
+
const parsed = JSON.parse(body);
|
|
15067
|
+
if ("string" == typeof parsed.error && parsed.error.trim()) return `${prefix}: ${parsed.error} (${status})`;
|
|
15068
|
+
} catch {}
|
|
15069
|
+
return `${prefix}: ${status} ${body}`;
|
|
15070
|
+
}
|
|
15071
|
+
const ANVIL_GITIGNORE_ENTRY = "/.anvil/";
|
|
15072
|
+
async function ensureProjectGitignoreIgnoresAnvilDir(projectRoot) {
|
|
15073
|
+
const rootGitignorePath = external_path_default().join(projectRoot, ".gitignore");
|
|
15074
|
+
try {
|
|
15075
|
+
const existing = await external_fs_.promises.readFile(rootGitignorePath, "utf8");
|
|
15076
|
+
if (existing.includes(ANVIL_GITIGNORE_ENTRY)) return false;
|
|
15077
|
+
const prefix = existing.endsWith("\n") || 0 === existing.length ? "" : "\n";
|
|
15078
|
+
await external_fs_.promises.writeFile(rootGitignorePath, `${existing}${prefix}${ANVIL_GITIGNORE_ENTRY}\n`, "utf8");
|
|
15079
|
+
return true;
|
|
15080
|
+
} catch (error) {
|
|
15081
|
+
if ("ENOENT" !== error.code) throw error;
|
|
15082
|
+
await external_fs_.promises.writeFile(rootGitignorePath, `${ANVIL_GITIGNORE_ENTRY}\n`, "utf8");
|
|
15083
|
+
return true;
|
|
14976
15084
|
}
|
|
14977
|
-
|
|
14978
|
-
|
|
14979
|
-
|
|
14980
|
-
|
|
14981
|
-
|
|
14982
|
-
|
|
14983
|
-
|
|
14984
|
-
|
|
14985
|
-
|
|
14986
|
-
|
|
14987
|
-
|
|
14988
|
-
|
|
14989
|
-
|
|
14990
|
-
|
|
14991
|
-
|
|
14992
|
-
|
|
15085
|
+
}
|
|
15086
|
+
const ANVIL_DEPS_DIR = ".anvil/deps";
|
|
15087
|
+
const ANVIL_DEPS_MANIFEST = "manifest.json";
|
|
15088
|
+
const DEPS_MANIFEST_VERSION = 2;
|
|
15089
|
+
async function fetchAllDependencies(appId, anvilUrl, options = {}) {
|
|
15090
|
+
const { commit, includeDocs = true, knownDependencies = [] } = options;
|
|
15091
|
+
anvilUrl ??= await auth_resolveAuthAnvilUrl();
|
|
15092
|
+
const token = await auth_getValidAuthToken(anvilUrl);
|
|
15093
|
+
const body = {
|
|
15094
|
+
include_docs: includeDocs,
|
|
15095
|
+
known_dependencies: knownDependencies
|
|
15096
|
+
};
|
|
15097
|
+
if (commit) body.commit = commit;
|
|
15098
|
+
const resp = await fetch(`${anvilUrl}/ide/api/_/apps/${appId}/resolved-dependencies`, {
|
|
15099
|
+
method: "POST",
|
|
15100
|
+
headers: {
|
|
15101
|
+
Authorization: `Bearer ${token}`,
|
|
15102
|
+
"Content-Type": "application/json"
|
|
15103
|
+
},
|
|
15104
|
+
body: JSON.stringify(body)
|
|
15105
|
+
});
|
|
15106
|
+
if (!resp.ok) {
|
|
15107
|
+
const errorBody = await resp.text();
|
|
15108
|
+
throw new Error(formatHttpError("Failed to fetch dependencies", resp.status, errorBody));
|
|
14993
15109
|
}
|
|
14994
|
-
|
|
14995
|
-
|
|
14996
|
-
|
|
14997
|
-
|
|
14998
|
-
|
|
14999
|
-
|
|
15000
|
-
|
|
15001
|
-
|
|
15002
|
-
|
|
15110
|
+
return await resp.json();
|
|
15111
|
+
}
|
|
15112
|
+
async function refreshDependencyCache(projectRoot, appId, anvilUrl, options = {}) {
|
|
15113
|
+
auth_setRepoContext(projectRoot);
|
|
15114
|
+
anvilUrl ??= await auth_resolveAuthAnvilUrl();
|
|
15115
|
+
const includeDocs = options.includeDocs ?? true;
|
|
15116
|
+
const knownDependencies = await getKnownDependenciesForCache(projectRoot, includeDocs);
|
|
15117
|
+
const response = await fetchAllDependencies(appId, anvilUrl, {
|
|
15118
|
+
commit: options.commit,
|
|
15119
|
+
includeDocs,
|
|
15120
|
+
knownDependencies
|
|
15121
|
+
});
|
|
15122
|
+
if (!response.resolved_dependencies.length) {
|
|
15123
|
+
await clearDepsCache(projectRoot);
|
|
15124
|
+
return {
|
|
15125
|
+
response,
|
|
15126
|
+
addedGitignoreEntry: false
|
|
15127
|
+
};
|
|
15003
15128
|
}
|
|
15004
|
-
|
|
15005
|
-
|
|
15006
|
-
|
|
15007
|
-
|
|
15008
|
-
|
|
15009
|
-
|
|
15010
|
-
|
|
15011
|
-
|
|
15012
|
-
|
|
15013
|
-
|
|
15014
|
-
|
|
15015
|
-
|
|
15016
|
-
|
|
15017
|
-
|
|
15018
|
-
|
|
15019
|
-
|
|
15129
|
+
const addedGitignoreEntry = await ensureProjectGitignoreIgnoresAnvilDir(projectRoot);
|
|
15130
|
+
await writeAllDepsToCache(projectRoot, response, {
|
|
15131
|
+
includeDocs
|
|
15132
|
+
});
|
|
15133
|
+
return {
|
|
15134
|
+
response,
|
|
15135
|
+
addedGitignoreEntry
|
|
15136
|
+
};
|
|
15137
|
+
}
|
|
15138
|
+
function depsDir(projectRoot) {
|
|
15139
|
+
return external_path_default().join(projectRoot, ANVIL_DEPS_DIR);
|
|
15140
|
+
}
|
|
15141
|
+
function depsManifestPath(projectRoot) {
|
|
15142
|
+
return external_path_default().join(depsDir(projectRoot), ANVIL_DEPS_MANIFEST);
|
|
15143
|
+
}
|
|
15144
|
+
function isResolvedDependencyManifestEntry(value) {
|
|
15145
|
+
if (!value || "object" != typeof value) return false;
|
|
15146
|
+
const entry = value;
|
|
15147
|
+
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);
|
|
15148
|
+
}
|
|
15149
|
+
function isCachedDependencyManifestEntry(value) {
|
|
15150
|
+
if (!isResolvedDependencyManifestEntry(value)) return false;
|
|
15151
|
+
const entry = value;
|
|
15152
|
+
return "string" == typeof entry.package_name && entry.package_name.length > 0;
|
|
15153
|
+
}
|
|
15154
|
+
function isDepsCacheManifest(value) {
|
|
15155
|
+
if (!value || "object" != typeof value) return false;
|
|
15156
|
+
const manifest = value;
|
|
15157
|
+
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);
|
|
15158
|
+
}
|
|
15159
|
+
async function readDepsCacheManifest(projectRoot) {
|
|
15160
|
+
try {
|
|
15161
|
+
const raw = await external_fs_promises_default().readFile(depsManifestPath(projectRoot), "utf-8");
|
|
15162
|
+
const parsed = JSON.parse(raw);
|
|
15163
|
+
return isDepsCacheManifest(parsed) ? parsed : void 0;
|
|
15164
|
+
} catch {
|
|
15165
|
+
return;
|
|
15020
15166
|
}
|
|
15021
|
-
|
|
15022
|
-
|
|
15023
|
-
|
|
15024
|
-
|
|
15025
|
-
|
|
15026
|
-
|
|
15027
|
-
|
|
15028
|
-
|
|
15029
|
-
|
|
15167
|
+
}
|
|
15168
|
+
async function getKnownDependenciesForCache(projectRoot, includeDocs) {
|
|
15169
|
+
const manifest = await readDepsCacheManifest(projectRoot);
|
|
15170
|
+
if (!manifest || manifest.includeDocs !== includeDocs) return [];
|
|
15171
|
+
return manifest.resolved_dependencies.map(({ app_id, commit_id })=>({
|
|
15172
|
+
app_id,
|
|
15173
|
+
commit_id
|
|
15174
|
+
}));
|
|
15175
|
+
}
|
|
15176
|
+
function getDependencyWatchSubscriptionsFromManifest(manifest) {
|
|
15177
|
+
if (!manifest) return [];
|
|
15178
|
+
const cachedByAppId = new Map(manifest.cached_dependencies.map((dep)=>[
|
|
15179
|
+
dep.app_id,
|
|
15180
|
+
dep
|
|
15181
|
+
]));
|
|
15182
|
+
return manifest.resolved_dependencies.flatMap((dep)=>{
|
|
15183
|
+
if (!dep.branch) return [];
|
|
15184
|
+
return [
|
|
15185
|
+
{
|
|
15186
|
+
appId: dep.app_id,
|
|
15187
|
+
branch: dep.branch,
|
|
15188
|
+
packageName: cachedByAppId.get(dep.app_id)?.package_name
|
|
15189
|
+
}
|
|
15190
|
+
];
|
|
15191
|
+
});
|
|
15192
|
+
}
|
|
15193
|
+
function normalizeAnvilYamlDependenciesFromContent(content) {
|
|
15194
|
+
const parsed = external_js_yaml_default().load(content);
|
|
15195
|
+
if (!parsed || "object" != typeof parsed || !Array.isArray(parsed.dependencies)) return [];
|
|
15196
|
+
return normalizeAnvilYamlDependenciesValue(parsed.dependencies);
|
|
15197
|
+
}
|
|
15198
|
+
function normalizeAnvilYamlDependenciesValue(value) {
|
|
15199
|
+
if (!Array.isArray(value)) return [];
|
|
15200
|
+
return value.map(normalizeForComparison);
|
|
15201
|
+
}
|
|
15202
|
+
async function readAnvilYamlDependencies(projectRoot) {
|
|
15203
|
+
try {
|
|
15204
|
+
const content = await external_fs_promises_default().readFile(external_path_default().join(projectRoot, "anvil.yaml"), "utf-8");
|
|
15205
|
+
return normalizeAnvilYamlDependenciesFromContent(content);
|
|
15206
|
+
} catch {
|
|
15207
|
+
return [];
|
|
15030
15208
|
}
|
|
15031
|
-
|
|
15032
|
-
|
|
15033
|
-
|
|
15034
|
-
|
|
15035
|
-
|
|
15036
|
-
|
|
15037
|
-
|
|
15038
|
-
|
|
15209
|
+
}
|
|
15210
|
+
function anvilYamlDependenciesEqual(left, right) {
|
|
15211
|
+
return deepEqual(left, right);
|
|
15212
|
+
}
|
|
15213
|
+
function normalizeForComparison(value) {
|
|
15214
|
+
if (Array.isArray(value)) return value.map(normalizeForComparison);
|
|
15215
|
+
if (value && "object" == typeof value) return Object.fromEntries(Object.entries(value).sort(([left], [right])=>left.localeCompare(right)).map(([key, entryValue])=>[
|
|
15216
|
+
key,
|
|
15217
|
+
normalizeForComparison(entryValue)
|
|
15218
|
+
]));
|
|
15219
|
+
return value;
|
|
15220
|
+
}
|
|
15221
|
+
function cachedManifestEntry(dep, packageName) {
|
|
15222
|
+
return {
|
|
15223
|
+
app_id: dep.app_id,
|
|
15224
|
+
commit_id: dep.commit_id,
|
|
15225
|
+
...dep.branch ? {
|
|
15226
|
+
branch: dep.branch
|
|
15227
|
+
} : {},
|
|
15228
|
+
package_name: packageName
|
|
15229
|
+
};
|
|
15230
|
+
}
|
|
15231
|
+
function safeDependencyPath(filePath, kind) {
|
|
15232
|
+
const normalizedPath = external_path_default().normalize(filePath);
|
|
15233
|
+
if (external_path_default().isAbsolute(normalizedPath) || normalizedPath.startsWith("..")) throw new Error(`Invalid dependency ${kind} path: ${filePath}`);
|
|
15234
|
+
return normalizedPath;
|
|
15235
|
+
}
|
|
15236
|
+
function dependencyPythonPath(name, kind) {
|
|
15237
|
+
const parts = name.split(".");
|
|
15238
|
+
if (0 === parts.length || parts.some((part)=>!part || "." === part || ".." === part || part.includes("/") || part.includes("\\"))) throw new Error(`Invalid dependency ${kind} name: ${name}`);
|
|
15239
|
+
return external_path_default().join(...parts);
|
|
15240
|
+
}
|
|
15241
|
+
async function writeDepToCache(projectRoot, dep) {
|
|
15242
|
+
const depDir = external_path_default().join(projectRoot, ANVIL_DEPS_DIR, dep.package_name);
|
|
15243
|
+
await external_fs_promises_default().rm(depDir, {
|
|
15244
|
+
recursive: true,
|
|
15245
|
+
force: true
|
|
15246
|
+
});
|
|
15247
|
+
await external_fs_promises_default().mkdir(external_path_default().join(depDir, "client_code"), {
|
|
15248
|
+
recursive: true
|
|
15249
|
+
});
|
|
15250
|
+
await external_fs_promises_default().mkdir(external_path_default().join(depDir, "server_code"), {
|
|
15251
|
+
recursive: true
|
|
15252
|
+
});
|
|
15253
|
+
await external_fs_promises_default().writeFile(external_path_default().join(depDir, "anvil.yaml"), external_js_yaml_default().dump({
|
|
15254
|
+
package_name: dep.package_name
|
|
15255
|
+
}));
|
|
15256
|
+
for (const mod of dep.modules ?? []){
|
|
15257
|
+
const modulePath = external_path_default().join(depDir, "client_code", dependencyPythonPath(mod.name, "module"));
|
|
15258
|
+
if (mod.is_package) {
|
|
15259
|
+
await external_fs_promises_default().mkdir(modulePath, {
|
|
15260
|
+
recursive: true
|
|
15261
|
+
});
|
|
15262
|
+
await external_fs_promises_default().writeFile(external_path_default().join(modulePath, "__init__.py"), mod.code);
|
|
15263
|
+
} else {
|
|
15264
|
+
const moduleFile = `${modulePath}.py`;
|
|
15265
|
+
await external_fs_promises_default().mkdir(external_path_default().dirname(moduleFile), {
|
|
15266
|
+
recursive: true
|
|
15267
|
+
});
|
|
15268
|
+
await external_fs_promises_default().writeFile(moduleFile, mod.code);
|
|
15039
15269
|
}
|
|
15040
15270
|
}
|
|
15041
|
-
|
|
15042
|
-
|
|
15043
|
-
|
|
15044
|
-
|
|
15045
|
-
|
|
15046
|
-
|
|
15047
|
-
|
|
15048
|
-
|
|
15049
|
-
|
|
15050
|
-
|
|
15051
|
-
|
|
15052
|
-
|
|
15053
|
-
|
|
15271
|
+
for (const form of dep.forms ?? []){
|
|
15272
|
+
const { code, class_name, is_package, ...formTemplate } = form;
|
|
15273
|
+
const formPath = external_path_default().join(depDir, "client_code", dependencyPythonPath(class_name, "form"));
|
|
15274
|
+
if (is_package) {
|
|
15275
|
+
await external_fs_promises_default().mkdir(formPath, {
|
|
15276
|
+
recursive: true
|
|
15277
|
+
});
|
|
15278
|
+
await external_fs_promises_default().writeFile(external_path_default().join(formPath, "__init__.py"), code);
|
|
15279
|
+
await external_fs_promises_default().writeFile(external_path_default().join(formPath, "form_template.yaml"), external_js_yaml_default().dump(formTemplate));
|
|
15280
|
+
} else {
|
|
15281
|
+
const formCodeFile = `${formPath}.py`;
|
|
15282
|
+
await external_fs_promises_default().mkdir(external_path_default().dirname(formCodeFile), {
|
|
15283
|
+
recursive: true
|
|
15284
|
+
});
|
|
15285
|
+
await external_fs_promises_default().writeFile(formCodeFile, code);
|
|
15286
|
+
await external_fs_promises_default().writeFile(`${formPath}.yaml`, external_js_yaml_default().dump(formTemplate));
|
|
15054
15287
|
}
|
|
15055
15288
|
}
|
|
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);
|
|
15289
|
+
for (const mod of dep.server_modules ?? []){
|
|
15290
|
+
const modulePath = external_path_default().join(depDir, "server_code", dependencyPythonPath(mod.name, "server module"));
|
|
15291
|
+
if (mod.is_package) {
|
|
15292
|
+
await external_fs_promises_default().mkdir(modulePath, {
|
|
15293
|
+
recursive: true
|
|
15294
|
+
});
|
|
15295
|
+
await external_fs_promises_default().writeFile(external_path_default().join(modulePath, "__init__.py"), mod.code);
|
|
15296
|
+
} else {
|
|
15297
|
+
const moduleFile = `${modulePath}.py`;
|
|
15298
|
+
await external_fs_promises_default().mkdir(external_path_default().dirname(moduleFile), {
|
|
15299
|
+
recursive: true
|
|
15300
|
+
});
|
|
15301
|
+
await external_fs_promises_default().writeFile(moduleFile, mod.code);
|
|
15081
15302
|
}
|
|
15082
15303
|
}
|
|
15083
|
-
|
|
15084
|
-
const
|
|
15085
|
-
|
|
15304
|
+
for (const asset of dep.assets ?? []){
|
|
15305
|
+
const targetPath = external_path_default().join(depDir, "theme", "assets", safeDependencyPath(asset.name, "asset"));
|
|
15306
|
+
await external_fs_promises_default().mkdir(external_path_default().dirname(targetPath), {
|
|
15307
|
+
recursive: true
|
|
15308
|
+
});
|
|
15309
|
+
await external_fs_promises_default().writeFile(targetPath, Buffer.from(asset.content, "base64"));
|
|
15086
15310
|
}
|
|
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) {}
|
|
15311
|
+
for (const doc of dep.docs ?? []){
|
|
15312
|
+
const targetPath = external_path_default().join(depDir, safeDependencyPath(doc.path, "doc"));
|
|
15313
|
+
await external_fs_promises_default().mkdir(external_path_default().dirname(targetPath), {
|
|
15314
|
+
recursive: true
|
|
15315
|
+
});
|
|
15316
|
+
await external_fs_promises_default().writeFile(targetPath, doc.content);
|
|
15105
15317
|
}
|
|
15106
15318
|
}
|
|
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
|
-
|
|
15319
|
+
async function writeAllDepsToCache(projectRoot, response, options = {}) {
|
|
15320
|
+
const includeDocs = options.includeDocs ?? true;
|
|
15321
|
+
const manifest = await readDepsCacheManifest(projectRoot);
|
|
15322
|
+
const canReuseExistingCache = manifest?.includeDocs === includeDocs;
|
|
15323
|
+
if (!canReuseExistingCache) await clearDepsCache(projectRoot);
|
|
15324
|
+
const previousCached = canReuseExistingCache ? manifest.cached_dependencies : [];
|
|
15325
|
+
const resolvedAppIds = new Set(response.resolved_dependencies.map((dep)=>dep.app_id));
|
|
15326
|
+
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), {
|
|
15327
|
+
recursive: true,
|
|
15328
|
+
force: true
|
|
15329
|
+
});
|
|
15330
|
+
for (const dep of response.dependencies)await writeDepToCache(projectRoot, dep);
|
|
15331
|
+
const returnedByAppId = new Map(response.dependencies.map((dep)=>[
|
|
15332
|
+
dep.app_id,
|
|
15333
|
+
dep
|
|
15334
|
+
]));
|
|
15335
|
+
const previousByAppId = new Map(previousCached.map((dep)=>[
|
|
15336
|
+
dep.app_id,
|
|
15337
|
+
dep
|
|
15338
|
+
]));
|
|
15339
|
+
const cachedDependencies = response.resolved_dependencies.map((dep)=>{
|
|
15340
|
+
const returned = returnedByAppId.get(dep.app_id);
|
|
15341
|
+
if (returned) return cachedManifestEntry(returned, returned.package_name);
|
|
15342
|
+
const previous = previousByAppId.get(dep.app_id);
|
|
15343
|
+
if (!previous) return;
|
|
15344
|
+
return cachedManifestEntry(dep, previous.package_name);
|
|
15345
|
+
}).filter((dep)=>void 0 !== dep);
|
|
15346
|
+
const newManifest = {
|
|
15347
|
+
version: DEPS_MANIFEST_VERSION,
|
|
15348
|
+
includeDocs,
|
|
15349
|
+
source_dependencies: await readAnvilYamlDependencies(projectRoot),
|
|
15350
|
+
resolved_dependencies: response.resolved_dependencies,
|
|
15351
|
+
cached_dependencies: cachedDependencies
|
|
15352
|
+
};
|
|
15353
|
+
await external_fs_promises_default().mkdir(depsDir(projectRoot), {
|
|
15354
|
+
recursive: true
|
|
15355
|
+
});
|
|
15356
|
+
await external_fs_promises_default().writeFile(depsManifestPath(projectRoot), `${JSON.stringify(newManifest, null, 2)}\n`);
|
|
15357
|
+
}
|
|
15358
|
+
async function clearDepsCache(projectRoot) {
|
|
15359
|
+
await external_fs_promises_default().rm(depsDir(projectRoot), {
|
|
15360
|
+
recursive: true,
|
|
15361
|
+
force: true
|
|
15362
|
+
});
|
|
15148
15363
|
}
|
|
15149
15364
|
const external_chokidar_namespaceObject = require("chokidar");
|
|
15150
15365
|
var external_chokidar_default = /*#__PURE__*/ __webpack_require__.n(external_chokidar_namespaceObject);
|
|
@@ -16912,7 +17127,7 @@ print(json.dumps({"issues": issues}))
|
|
|
16912
17127
|
}
|
|
16913
17128
|
function validateScheduledTasks(value, path) {
|
|
16914
17129
|
const issues = [];
|
|
16915
|
-
if (
|
|
17130
|
+
if (null == value) return issues;
|
|
16916
17131
|
if (!Array.isArray(value)) {
|
|
16917
17132
|
validators_pushIssue(issues, path, "must be an array");
|
|
16918
17133
|
return issues;
|
|
@@ -18411,6 +18626,15 @@ print(json.dumps({"issues": issues}))
|
|
|
18411
18626
|
this.hasPendingChanges = true;
|
|
18412
18627
|
await this.processSaveBatchWithEvents();
|
|
18413
18628
|
}
|
|
18629
|
+
async flush() {
|
|
18630
|
+
const requireReady = ()=>{
|
|
18631
|
+
if (this.config.isPaused() || this.config.isCleanedUp() || !this.config.isSettlePeriodOver()) throw new Error("Cannot flush saves while watching is paused, closed, or changing branch");
|
|
18632
|
+
};
|
|
18633
|
+
requireReady();
|
|
18634
|
+
await this.forceSave();
|
|
18635
|
+
requireReady();
|
|
18636
|
+
if (this.hasPendingChanges) throw new Error("Saves remain pending");
|
|
18637
|
+
}
|
|
18414
18638
|
cleanup() {
|
|
18415
18639
|
if (this.hasPendingChanges) {
|
|
18416
18640
|
logger_logger.progressEnd("sync");
|
|
@@ -18507,10 +18731,7 @@ print(json.dumps({"issues": issues}))
|
|
|
18507
18731
|
status = await this.config.gitService.getStatus();
|
|
18508
18732
|
} catch (e) {
|
|
18509
18733
|
logger_logger.error(external_chalk_default().red(`Error reading git status: ${errors_getErrorMessage(e)}`));
|
|
18510
|
-
|
|
18511
|
-
skipped: true,
|
|
18512
|
-
reason: "Git status error"
|
|
18513
|
-
};
|
|
18734
|
+
throw e;
|
|
18514
18735
|
}
|
|
18515
18736
|
let allChanges;
|
|
18516
18737
|
if (this.config.stagedOnly) {
|
|
@@ -19667,6 +19888,12 @@ print(json.dumps({"issues": issues}))
|
|
|
19667
19888
|
if (!this.saveProcessor) return;
|
|
19668
19889
|
return this.saveProcessor.forceSave();
|
|
19669
19890
|
}
|
|
19891
|
+
async flushSaves() {
|
|
19892
|
+
if (!this.saveProcessor || this.isSwitchingForEnvironment) throw new Error("App synchronization is not ready");
|
|
19893
|
+
const branch = this.currentBranch;
|
|
19894
|
+
await this.saveProcessor.flush();
|
|
19895
|
+
if (this.isSwitchingForEnvironment || this.currentBranch !== branch || await this.gitService.getCurrentBranch() !== branch) throw new Error("App branch changed while flushing saves");
|
|
19896
|
+
}
|
|
19670
19897
|
async getSuccessMessage() {
|
|
19671
19898
|
try {
|
|
19672
19899
|
const info = await this.gitService.getCommitInfo();
|
|
@@ -20537,7 +20764,29 @@ print(json.dumps({"issues": issues}))
|
|
|
20537
20764
|
const response = await buildGitCredentialResponse(operation, request, options);
|
|
20538
20765
|
writeGitCredentialResponse(response);
|
|
20539
20766
|
}
|
|
20540
|
-
|
|
20767
|
+
const MODEL_TOKEN_LOCK_TIMEOUT_MS = 12000;
|
|
20768
|
+
const modelToken_defaultDeps = {
|
|
20769
|
+
getValidAuthToken: auth_getValidAuthToken,
|
|
20770
|
+
readAuthFromRepo: readAuthFromRepo,
|
|
20771
|
+
cwd: ()=>process.cwd()
|
|
20772
|
+
};
|
|
20773
|
+
async function getModelToken(options = {}) {
|
|
20774
|
+
const deps = options.deps ?? modelToken_defaultDeps;
|
|
20775
|
+
const repoPath = options.repoPath ?? deps.cwd();
|
|
20776
|
+
auth_setRepoContext(repoPath);
|
|
20777
|
+
if (!process.env["ANVIL_AUTH_FILE_ENCRYPTION_KEY"]) throw new Error("ANVIL_AUTH_FILE_ENCRYPTION_KEY is not set; cannot read repo auth tokens.");
|
|
20778
|
+
const auth = await deps.readAuthFromRepo(repoPath);
|
|
20779
|
+
if (!auth) throw new Error(`No Anvil auth tokens found for the repository at ${repoPath}.`);
|
|
20780
|
+
return deps.getValidAuthToken(auth.anvilUrl, auth.username, {
|
|
20781
|
+
lock: {
|
|
20782
|
+
timeoutMs: options.lockTimeoutMs ?? MODEL_TOKEN_LOCK_TIMEOUT_MS
|
|
20783
|
+
}
|
|
20784
|
+
});
|
|
20785
|
+
}
|
|
20786
|
+
async function executeModelTokenOperation(options = {}) {
|
|
20787
|
+
const token = await getModelToken(options);
|
|
20788
|
+
process.stdout.write(`${token}\n`);
|
|
20789
|
+
}
|
|
20541
20790
|
async function watch_decideFallbackUrl(explicitUrl, availableUrls) {
|
|
20542
20791
|
if (explicitUrl) return {
|
|
20543
20792
|
source: "explicit",
|
|
@@ -20748,7 +20997,6 @@ print(json.dumps({"issues": issues}))
|
|
|
20748
20997
|
remoteName
|
|
20749
20998
|
};
|
|
20750
20999
|
}
|
|
20751
|
-
const api_DEFAULT_ANVIL_URL = resolveAnvilUrl();
|
|
20752
21000
|
async function api_checkUncommittedChanges(repoPath) {
|
|
20753
21001
|
try {
|
|
20754
21002
|
const git = esm_default(repoPath);
|
|
@@ -20797,9 +21045,10 @@ print(json.dumps({"issues": issues}))
|
|
|
20797
21045
|
}
|
|
20798
21046
|
}
|
|
20799
21047
|
async function src_api_watch(repoPath, appId, options = {}) {
|
|
20800
|
-
const { anvilUrl = api_DEFAULT_ANVIL_URL, gitUrl = anvilUrl, stagedOnly = false, username } = options;
|
|
20801
21048
|
repoPath = external_path_default().resolve(repoPath);
|
|
20802
21049
|
auth_setRepoContext(repoPath);
|
|
21050
|
+
const anvilUrl = options.anvilUrl ?? await auth_resolveAuthAnvilUrl();
|
|
21051
|
+
const { gitUrl = anvilUrl, stagedOnly = false, username } = options;
|
|
20803
21052
|
const storedEnvPid = options.environment?.envPid ? void 0 : await environment_readEnvironmentPid(repoPath);
|
|
20804
21053
|
const environment = options.environment ?? (storedEnvPid ? {
|
|
20805
21054
|
envPid: storedEnvPid
|
|
@@ -20914,6 +21163,7 @@ print(json.dumps({"issues": issues}))
|
|
|
20914
21163
|
}
|
|
20915
21164
|
})();
|
|
20916
21165
|
exports.ANVIL_SYNC_CLIENT_ID = __webpack_exports__.ANVIL_SYNC_CLIENT_ID;
|
|
21166
|
+
exports.AUTH_FILE_LOCK_DEFAULTS = __webpack_exports__.AUTH_FILE_LOCK_DEFAULTS;
|
|
20917
21167
|
exports.AnvilYamlValidationResult = __webpack_exports__.AnvilYamlValidationResult;
|
|
20918
21168
|
exports.AppIdCandidate = __webpack_exports__.AppIdCandidate;
|
|
20919
21169
|
exports.AppIdWithContext = __webpack_exports__.AppIdWithContext;
|
|
@@ -20925,11 +21175,15 @@ exports.CheckoutOptions = __webpack_exports__.CheckoutOptions;
|
|
|
20925
21175
|
exports.CheckoutResult = __webpack_exports__.CheckoutResult;
|
|
20926
21176
|
exports.DeviceAuthorizationResponse = __webpack_exports__.DeviceAuthorizationResponse;
|
|
20927
21177
|
exports.FormTemplateValidationResult = __webpack_exports__.FormTemplateValidationResult;
|
|
21178
|
+
exports.GetValidAuthTokenOptions = __webpack_exports__.GetValidAuthTokenOptions;
|
|
20928
21179
|
exports.LoginResult = __webpack_exports__.LoginResult;
|
|
20929
21180
|
exports.LogoutResult = __webpack_exports__.LogoutResult;
|
|
21181
|
+
exports.MODEL_TOKEN_HELPER_FILENAME = __webpack_exports__.MODEL_TOKEN_HELPER_FILENAME;
|
|
21182
|
+
exports.MODEL_TOKEN_LOCK_TIMEOUT_MS = __webpack_exports__.MODEL_TOKEN_LOCK_TIMEOUT_MS;
|
|
20930
21183
|
exports.OAuthTokenResponse = __webpack_exports__.OAuthTokenResponse;
|
|
20931
21184
|
exports.ParsedCheckoutInput = __webpack_exports__.ParsedCheckoutInput;
|
|
20932
21185
|
exports.PreferredEditor = __webpack_exports__.PreferredEditor;
|
|
21186
|
+
exports.REFRESH_REQUEST_TIMEOUT_MS = __webpack_exports__.REFRESH_REQUEST_TIMEOUT_MS;
|
|
20933
21187
|
exports.SettableConfigKey = __webpack_exports__.SettableConfigKey;
|
|
20934
21188
|
exports.TokenData = __webpack_exports__.TokenData;
|
|
20935
21189
|
exports.ValidateAppIdResponse = __webpack_exports__.ValidateAppIdResponse;
|
|
@@ -20950,6 +21204,7 @@ exports.detectAppIdsByCommitLookup = __webpack_exports__.detectAppIdsByCommitLoo
|
|
|
20950
21204
|
exports.detectAppIdsFromAllRemotes = __webpack_exports__.detectAppIdsFromAllRemotes;
|
|
20951
21205
|
exports.executeCheckout = __webpack_exports__.executeCheckout;
|
|
20952
21206
|
exports.executeGitCredentialOperation = __webpack_exports__.executeGitCredentialOperation;
|
|
21207
|
+
exports.executeModelTokenOperation = __webpack_exports__.executeModelTokenOperation;
|
|
20953
21208
|
exports.filterCandidates = __webpack_exports__.filterCandidates;
|
|
20954
21209
|
exports.formatCandidateLabel = __webpack_exports__.formatCandidateLabel;
|
|
20955
21210
|
exports.formatGitAuthDoctorReport = __webpack_exports__.formatGitAuthDoctorReport;
|
|
@@ -20963,12 +21218,15 @@ exports.getGitFetchUrl = __webpack_exports__.getGitFetchUrl;
|
|
|
20963
21218
|
exports.getGitPushUrl = __webpack_exports__.getGitPushUrl;
|
|
20964
21219
|
exports.getInstalledPreferredEditors = __webpack_exports__.getInstalledPreferredEditors;
|
|
20965
21220
|
exports.getLatestVersion = __webpack_exports__.getLatestVersion;
|
|
21221
|
+
exports.getModelToken = __webpack_exports__.getModelToken;
|
|
21222
|
+
exports.getModelTokenHelperScript = __webpack_exports__.getModelTokenHelperScript;
|
|
20966
21223
|
exports.getPreferredEditorCommand = __webpack_exports__.getPreferredEditorCommand;
|
|
20967
21224
|
exports.getSettableConfigKeys = __webpack_exports__.getSettableConfigKeys;
|
|
20968
21225
|
exports.getValidAuthToken = __webpack_exports__.getValidAuthToken;
|
|
20969
21226
|
exports.getWebSocketUrl = __webpack_exports__.getWebSocketUrl;
|
|
20970
21227
|
exports.hasTokensForUrl = __webpack_exports__.hasTokensForUrl;
|
|
20971
21228
|
exports.inspectCredentialHelperCommand = __webpack_exports__.inspectCredentialHelperCommand;
|
|
21229
|
+
exports.installModelTokenHelperScript = __webpack_exports__.installModelTokenHelperScript;
|
|
20972
21230
|
exports.isCommandAvailable = __webpack_exports__.isCommandAvailable;
|
|
20973
21231
|
exports.isDirectoryNonEmpty = __webpack_exports__.isDirectoryNonEmpty;
|
|
20974
21232
|
exports.isPathInsideGitRepo = __webpack_exports__.isPathInsideGitRepo;
|
|
@@ -21004,9 +21262,11 @@ exports.validatePath = __webpack_exports__.validatePath;
|
|
|
21004
21262
|
exports.verifyAndStoreTokens = __webpack_exports__.verifyAndStoreTokens;
|
|
21005
21263
|
exports.verifyAuth = __webpack_exports__.verifyAuth;
|
|
21006
21264
|
exports.watch = __webpack_exports__.watch;
|
|
21265
|
+
exports.withRepoAuthFileLock = __webpack_exports__.withRepoAuthFileLock;
|
|
21007
21266
|
exports.writeEnvironmentPid = __webpack_exports__.writeEnvironmentPid;
|
|
21008
21267
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
21009
21268
|
"ANVIL_SYNC_CLIENT_ID",
|
|
21269
|
+
"AUTH_FILE_LOCK_DEFAULTS",
|
|
21010
21270
|
"AnvilYamlValidationResult",
|
|
21011
21271
|
"AppIdCandidate",
|
|
21012
21272
|
"AppIdWithContext",
|
|
@@ -21018,11 +21278,15 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
21018
21278
|
"CheckoutResult",
|
|
21019
21279
|
"DeviceAuthorizationResponse",
|
|
21020
21280
|
"FormTemplateValidationResult",
|
|
21281
|
+
"GetValidAuthTokenOptions",
|
|
21021
21282
|
"LoginResult",
|
|
21022
21283
|
"LogoutResult",
|
|
21284
|
+
"MODEL_TOKEN_HELPER_FILENAME",
|
|
21285
|
+
"MODEL_TOKEN_LOCK_TIMEOUT_MS",
|
|
21023
21286
|
"OAuthTokenResponse",
|
|
21024
21287
|
"ParsedCheckoutInput",
|
|
21025
21288
|
"PreferredEditor",
|
|
21289
|
+
"REFRESH_REQUEST_TIMEOUT_MS",
|
|
21026
21290
|
"SettableConfigKey",
|
|
21027
21291
|
"TokenData",
|
|
21028
21292
|
"ValidateAppIdResponse",
|
|
@@ -21043,6 +21307,7 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
21043
21307
|
"detectAppIdsFromAllRemotes",
|
|
21044
21308
|
"executeCheckout",
|
|
21045
21309
|
"executeGitCredentialOperation",
|
|
21310
|
+
"executeModelTokenOperation",
|
|
21046
21311
|
"filterCandidates",
|
|
21047
21312
|
"formatCandidateLabel",
|
|
21048
21313
|
"formatGitAuthDoctorReport",
|
|
@@ -21056,12 +21321,15 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
21056
21321
|
"getGitPushUrl",
|
|
21057
21322
|
"getInstalledPreferredEditors",
|
|
21058
21323
|
"getLatestVersion",
|
|
21324
|
+
"getModelToken",
|
|
21325
|
+
"getModelTokenHelperScript",
|
|
21059
21326
|
"getPreferredEditorCommand",
|
|
21060
21327
|
"getSettableConfigKeys",
|
|
21061
21328
|
"getValidAuthToken",
|
|
21062
21329
|
"getWebSocketUrl",
|
|
21063
21330
|
"hasTokensForUrl",
|
|
21064
21331
|
"inspectCredentialHelperCommand",
|
|
21332
|
+
"installModelTokenHelperScript",
|
|
21065
21333
|
"isCommandAvailable",
|
|
21066
21334
|
"isDirectoryNonEmpty",
|
|
21067
21335
|
"isPathInsideGitRepo",
|
|
@@ -21097,6 +21365,7 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
21097
21365
|
"verifyAndStoreTokens",
|
|
21098
21366
|
"verifyAuth",
|
|
21099
21367
|
"watch",
|
|
21368
|
+
"withRepoAuthFileLock",
|
|
21100
21369
|
"writeEnvironmentPid"
|
|
21101
21370
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
21102
21371
|
Object.defineProperty(exports, '__esModule', {
|