/* THIS IS A GENERATED/BUNDLED FILE BY ESBUILD if you want to view the source, please visit the github repository of this plugin */ var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __esm = (fn, res) => function __init() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // node_modules/before-after-hook/lib/register.js var require_register = __commonJS({ "node_modules/before-after-hook/lib/register.js"(exports, module2) { module2.exports = register; function register(state, name, method, options) { if (typeof method !== "function") { throw new Error("method for before hook must be a function"); } if (!options) { options = {}; } if (Array.isArray(name)) { return name.reverse().reduce(function(callback, name2) { return register.bind(null, state, name2, callback, options); }, method)(); } return Promise.resolve().then(function() { if (!state.registry[name]) { return method(options); } return state.registry[name].reduce(function(method2, registered) { return registered.hook.bind(null, method2, options); }, method)(); }); } } }); // node_modules/before-after-hook/lib/add.js var require_add = __commonJS({ "node_modules/before-after-hook/lib/add.js"(exports, module2) { module2.exports = addHook; function addHook(state, kind, name, hook2) { var orig = hook2; if (!state.registry[name]) { state.registry[name] = []; } if (kind === "before") { hook2 = function(method, options) { return Promise.resolve().then(orig.bind(null, options)).then(method.bind(null, options)); }; } if (kind === "after") { hook2 = function(method, options) { var result; return Promise.resolve().then(method.bind(null, options)).then(function(result_) { result = result_; return orig(result, options); }).then(function() { return result; }); }; } if (kind === "error") { hook2 = function(method, options) { return Promise.resolve().then(method.bind(null, options)).catch(function(error) { return orig(error, options); }); }; } state.registry[name].push({ hook: hook2, orig }); } } }); // node_modules/before-after-hook/lib/remove.js var require_remove = __commonJS({ "node_modules/before-after-hook/lib/remove.js"(exports, module2) { module2.exports = removeHook; function removeHook(state, name, method) { if (!state.registry[name]) { return; } var index = state.registry[name].map(function(registered) { return registered.orig; }).indexOf(method); if (index === -1) { return; } state.registry[name].splice(index, 1); } } }); // node_modules/before-after-hook/index.js var require_before_after_hook = __commonJS({ "node_modules/before-after-hook/index.js"(exports, module2) { var register = require_register(); var addHook = require_add(); var removeHook = require_remove(); var bind = Function.bind; var bindable = bind.bind(bind); function bindApi(hook2, state, name) { var removeHookRef = bindable(removeHook, null).apply( null, name ? [state, name] : [state] ); hook2.api = { remove: removeHookRef }; hook2.remove = removeHookRef; ["before", "error", "after", "wrap"].forEach(function(kind) { var args = name ? [state, kind, name] : [state, kind]; hook2[kind] = hook2.api[kind] = bindable(addHook, null).apply(null, args); }); } function HookSingular() { var singularHookName = "h"; var singularHookState = { registry: {} }; var singularHook = register.bind(null, singularHookState, singularHookName); bindApi(singularHook, singularHookState, singularHookName); return singularHook; } function HookCollection() { var state = { registry: {} }; var hook2 = register.bind(null, state); bindApi(hook2, state); return hook2; } var collectionHookDeprecationMessageDisplayed = false; function Hook() { if (!collectionHookDeprecationMessageDisplayed) { console.warn( '[before-after-hook]: "Hook()" repurposing warning, use "Hook.Collection()". Read more: https://git.io/upgrade-before-after-hook-to-1.4' ); collectionHookDeprecationMessageDisplayed = true; } return HookCollection(); } Hook.Singular = HookSingular.bind(); Hook.Collection = HookCollection.bind(); module2.exports = Hook; module2.exports.Hook = Hook; module2.exports.Singular = Hook.Singular; module2.exports.Collection = Hook.Collection; } }); // node_modules/node-fetch/browser.js var require_browser = __commonJS({ "node_modules/node-fetch/browser.js"(exports, module2) { "use strict"; var getGlobal = function() { if (typeof self !== "undefined") { return self; } if (typeof window !== "undefined") { return window; } if (typeof global !== "undefined") { return global; } throw new Error("unable to locate global object"); }; var globalObject = getGlobal(); module2.exports = exports = globalObject.fetch; if (globalObject.fetch) { exports.default = globalObject.fetch.bind(globalObject); } exports.Headers = globalObject.Headers; exports.Request = globalObject.Request; exports.Response = globalObject.Response; } }); // node_modules/wrappy/wrappy.js var require_wrappy = __commonJS({ "node_modules/wrappy/wrappy.js"(exports, module2) { module2.exports = wrappy; function wrappy(fn, cb) { if (fn && cb) return wrappy(fn)(cb); if (typeof fn !== "function") throw new TypeError("need wrapper function"); Object.keys(fn).forEach(function(k) { wrapper[k] = fn[k]; }); return wrapper; function wrapper() { var args = new Array(arguments.length); for (var i = 0; i < args.length; i++) { args[i] = arguments[i]; } var ret = fn.apply(this, args); var cb2 = args[args.length - 1]; if (typeof ret === "function" && ret !== cb2) { Object.keys(cb2).forEach(function(k) { ret[k] = cb2[k]; }); } return ret; } } } }); // node_modules/once/once.js var require_once = __commonJS({ "node_modules/once/once.js"(exports, module2) { var wrappy = require_wrappy(); module2.exports = wrappy(once2); module2.exports.strict = wrappy(onceStrict); once2.proto = once2(function() { Object.defineProperty(Function.prototype, "once", { value: function() { return once2(this); }, configurable: true }); Object.defineProperty(Function.prototype, "onceStrict", { value: function() { return onceStrict(this); }, configurable: true }); }); function once2(fn) { var f = function() { if (f.called) return f.value; f.called = true; return f.value = fn.apply(this, arguments); }; f.called = false; return f; } function onceStrict(fn) { var f = function() { if (f.called) throw new Error(f.onceError); f.called = true; return f.value = fn.apply(this, arguments); }; var name = fn.name || "Function wrapped with `once`"; f.onceError = name + " shouldn't be called more than once"; f.called = false; return f; } } }); // i18n-simple.ts function detectObsidianLanguage() { var _a, _b, _c, _d, _e, _f; const obsidianLang = localStorage.getItem("language") || ((_d = (_c = (_b = (_a = window.app) == null ? void 0 : _a.vault) == null ? void 0 : _b.adapter) == null ? void 0 : _c.path) == null ? void 0 : _d.locale) || ((_e = window.moment) == null ? void 0 : _e.locale()); const browserLang = navigator.language || ((_f = navigator.languages) == null ? void 0 : _f[0]) || "en"; if ((obsidianLang == null ? void 0 : obsidianLang.includes("zh")) || browserLang.startsWith("zh")) { return "zh"; } return "en"; } function getActualLanguage() { if (currentLanguage === "auto") { return detectObsidianLanguage(); } return currentLanguage; } function setLanguage(language) { currentLanguage = language; } function t(key, params) { const actualLang = getActualLanguage(); const translation = translations[actualLang][key]; if (!translation) { console.warn(`Translation missing for key: ${key}`); return key; } if (params) { return Object.entries(params).reduce((text, [paramKey, paramValue]) => { return text.replace(new RegExp(`\\{${paramKey}\\}`, "g"), String(paramValue)); }, translation); } return translation; } function getSupportedLanguages() { const detectedLang = detectObsidianLanguage(); const detectedLangText = detectedLang === "zh" ? "\u4E2D\u6587" : "English"; const currentLang = getActualLanguage(); const followText = currentLang === "zh" ? "\u8DDF\u968FObsidian" : "Follow Obsidian"; const autoLabel = `${followText} (${detectedLangText})`; return [ { value: "auto", label: autoLabel }, { value: "zh", label: "\u4E2D\u6587" }, { value: "en", label: "English" } ]; } var translations, currentLanguage; var init_i18n_simple = __esm({ "i18n-simple.ts"() { translations = { zh: { // Settings interface "settings.title": "Git\u540C\u6B65\u8BBE\u7F6E", "settings.language.name": "\u754C\u9762\u8BED\u8A00", "settings.language.desc": "\u9009\u62E9\u63D2\u4EF6\u754C\u9762\u663E\u793A\u8BED\u8A00", "settings.language.auto": "\u8DDF\u968FObsidian", "settings.github.token.name": "GitHub Personal Token", "settings.github.token.desc": "\u8F93\u5165\u4F60\u7684GitHub Personal Access Token", "settings.github.token.placeholder": "ghp_xxxxxxxxxxxx", "settings.github.repo.name": "GitHub\u4ED3\u5E93\u8DEF\u5F84", "settings.github.repo.desc": "\u652F\u6301\u4E24\u79CD\u683C\u5F0F\uFF1A\n1. https://github.com/\u7528\u6237\u540D/\u4ED3\u5E93\u540D/\u8DEF\u5F84\n2. \u7528\u6237\u540D/\u4ED3\u5E93\u540D/\u8DEF\u5F84", "settings.github.repo.placeholder": "https://github.com/Xheldon/git-folder-sync/data/_post", "settings.ribbon.name": "\u5C06\u63D2\u4EF6\u6309\u94AE\u663E\u793A\u5728\u4FA7\u8FB9\u680F", "settings.ribbon.desc": "\u5F00\u542F\u540E\uFF0C\u5728\u5DE6\u4FA7\u8FB9\u680F\u663E\u793A\u63D2\u4EF6\u6309\u94AE\uFF0C\u70B9\u51FB\u53EF\u5FEB\u901F\u6253\u5F00\u8BBE\u7F6E\u754C\u9762", "settings.save.name": "\u4FDD\u5B58\u8BBE\u7F6E", "settings.save.desc": "\u4FDD\u5B58\u5F53\u524D\u7684\u914D\u7F6E\u8BBE\u7F6E", "settings.save.button": "\u4FDD\u5B58\u8BBE\u7F6E", "settings.diagnose.name": "\u8BCA\u65ADVault\u6587\u4EF6", "settings.diagnose.desc": "\u68C0\u67E5\u5F53\u524DVault\u4E2D\u6709\u54EA\u4E9B\u6587\u4EF6\u53EF\u4EE5\u540C\u6B65", "settings.diagnose.button": "\u8BCA\u65AD", "settings.test.url.name": "\u6D4B\u8BD5\u4ED3\u5E93URL", "settings.test.url.desc": "\u9A8C\u8BC1GitHub\u4ED3\u5E93\u8DEF\u5F84\u683C\u5F0F\u662F\u5426\u6B63\u786E", "settings.test.url.button": "\u6D4B\u8BD5URL", "settings.test.url.loading": "\u6D4B\u8BD5\u4E2D...", "settings.sponsor.name": "\u{1F496} \u652F\u6301\u5F00\u53D1\u8005", "settings.sponsor.desc": "\u5982\u679C\u8FD9\u4E2A\u63D2\u4EF6\u5BF9\u4F60\u6709\u5E2E\u52A9\uFF0C\u6B22\u8FCE\u8BF7\u6211\u559D\u676F\u5496\u5561\uFF01\u4F60\u7684\u652F\u6301\u662F\u6211\u7EE7\u7EED\u5F00\u53D1\u7684\u52A8\u529B\u3002", "settings.sponsor.button": "\u{1F49D} PayPal \u8D5E\u52A9", "settings.sponsor.china.label": "\u{1F1E8}\u{1F1F3} \u4E2D\u56FD\u5927\u9646\u6350\u8D60\u6E20\u9053", "settings.sponsor.section.title": "\u8D5E\u52A9", "settings.danger.zone.title": "\u5371\u9669\u533A\u57DF", "settings.init.name": "\u521D\u59CB\u5316\u4ED3\u5E93", "settings.init.desc": "\u5F53\u672CVault\u4E3A\u7A7A\u7684\u65F6\u5019\u53EF\u7528\uFF0C\u5C06\u8FDC\u7AEF\u6587\u4EF6\u540C\u6B65\u5230\u672C\u5730", "settings.init.button": "\u521D\u59CB\u5316\u4ED3\u5E93", "settings.init.loading": "\u521D\u59CB\u5316\u4E2D...", "settings.sync.remote.to.local.name": "\u5F3A\u5236\u540C\u6B65\u8FDC\u7AEF\u8DEF\u5F84\u5230\u672C\u5730", "settings.sync.remote.to.local.desc": "\u5C06\u8FDC\u7AEF\u7684\u6587\u4EF6\u4E00\u80A1\u8111\u7684\u540C\u6B65\u5230\u672C\u5730\u7684Vault\u4E2D\uFF0C\u540C\u540D\u6587\u4EF6\u4F1A\u88AB\u8986\u76D6", "settings.sync.remote.to.local.button": "\u5F3A\u5236\u540C\u6B65\u5230\u672C\u5730", "settings.sync.remote.to.local.loading": "\u540C\u6B65\u4E2D...", "settings.sync.local.to.remote.name": "\u5F3A\u5236\u540C\u6B65\u672C\u5730\u6587\u4EF6\u5230\u8FDC\u7AEF", "settings.sync.local.to.remote.desc": "\u5C06\u672C\u5730\u7684Vault\u4E2D\u7684\u6240\u6709\u6587\u4EF6\u540C\u6B65\u5230\u8FDC\u7AEF\u914D\u7F6E\u7684\u8DEF\u5F84\u4E2D\uFF0C\u540C\u540D\u6587\u4EF6\u4F1A\u88AB\u8986\u76D6", "settings.sync.local.to.remote.button": "\u5F3A\u5236\u540C\u6B65\u5230\u8FDC\u7AEF", "settings.sync.local.to.remote.loading": "\u540C\u6B65\u4E2D...", "settings.clear.cache.name": "\u6E05\u7A7A\u6587\u4EF6\u7F13\u5B58", "settings.clear.cache.desc": "\u6E05\u7A7A\u6240\u6709\u6587\u4EF6\u72B6\u6001\u7F13\u5B58\uFF0C\u4E0B\u6B21\u67E5\u770B\u65F6\u5C06\u91CD\u65B0\u4ECEGitHub\u83B7\u53D6", "settings.clear.cache.button": "\u6E05\u7A7A\u7F13\u5B58", // COS settings "settings.image.section.title": "\u56FE\u7247\u5904\u7406", "settings.image.enable.name": "\u542F\u7528\u56FE\u7247\u5904\u7406\u529F\u80FD", "settings.image.enable.desc": "\u5F00\u542F\u540E\uFF0C\u7C98\u8D34\u56FE\u7247\u65F6\u5C06\u81EA\u52A8\u4E0A\u4F20\u5230\u4E91\u5B58\u50A8\u5E76\u66FF\u6362\u4E3A\u94FE\u63A5", "settings.cos.provider.section.title": "\u4E91\u670D\u52A1\u5546\u8BBE\u7F6E", "settings.image.upload.section.title": "\u56FE\u7247\u4E0A\u4F20\u8BBE\u7F6E", "settings.cos.provider.name": "\u4E91\u5B58\u50A8\u670D\u52A1\u5546", "settings.cos.provider.desc": "\u9009\u62E9\u8981\u4F7F\u7528\u7684\u4E91\u5BF9\u8C61\u5B58\u50A8\u670D\u52A1\u5546", "settings.cos.provider.aliyun": "\u963F\u91CC\u4E91 OSS", "settings.cos.provider.tencent": "\u817E\u8BAF\u4E91 COS", "settings.cos.provider.aws": "AWS S3", "settings.cos.provider.cloudflare": "Cloudflare R2", "settings.cos.secret.id.name": "Access Key ID / Secret ID", "settings.cos.secret.id.desc": "\u4E91\u5B58\u50A8\u670D\u52A1\u7684\u8BBF\u95EE\u5BC6\u94A5ID", "settings.cos.secret.id.placeholder": "\u8F93\u5165Access Key ID\u6216Secret ID", "settings.cos.secret.key.name": "Access Key Secret / Secret Key", "settings.cos.secret.key.desc": "\u4E91\u5B58\u50A8\u670D\u52A1\u7684\u8BBF\u95EE\u5BC6\u94A5", "settings.cos.secret.key.placeholder": "\u8F93\u5165Access Key Secret\u6216Secret Key", "settings.cos.bucket.name": "Bucket\u540D\u79F0", "settings.cos.bucket.desc": "\u5B58\u50A8\u6876\u540D\u79F0", "settings.cos.bucket.placeholder": "\u8F93\u5165bucket\u540D\u79F0", "settings.cos.endpoint.name": "Endpoint", "settings.cos.endpoint.desc": "\u670D\u52A1\u7AEF\u70B9\u5730\u5740\uFF08\u4EC5Cloudflare R2\u9700\u8981\uFF09", "settings.cos.endpoint.placeholder": "\u4F8B\u5982\uFF1Ahttps://accountid.r2.cloudflarestorage.com", "settings.cos.region.name": "Region", "settings.cos.region.desc": "\u533A\u57DF\u8BBE\u7F6E\uFF08\u6240\u6709\u670D\u52A1\u5546\u90FD\u9700\u8981\uFF09", "settings.cos.region.placeholder": "\u4F8B\u5982\uFF1Acn-hangzhou\u3001ap-beijing\u3001us-east-1", "settings.cos.cdn.name": "CDN\u5730\u5740", "settings.cos.cdn.desc": "CDN\u57DF\u540D\uFF0C\u7528\u4E8E\u751F\u6210\u8BBF\u95EE\u94FE\u63A5", "settings.cos.cdn.placeholder": "\u4F8B\u5982\uFF1Ahttps://cdn.example.com", "settings.cos.keep.local.name": "\u4FDD\u7559\u56FE\u7247\u5728\u672C\u5730", "settings.cos.keep.local.desc": "\u4E0A\u4F20\u540E\u662F\u5426\u5728\u672C\u5730\u4FDD\u7559\u56FE\u7247\u526F\u672C", "settings.cos.local.path.name": "\u672C\u5730\u5B58\u50A8\u8DEF\u5F84", "settings.cos.local.path.desc": "\u672C\u5730\u4FDD\u5B58\u56FE\u7247\u7684\u76EE\u5F55\uFF08\u76F8\u5BF9\u4E8Evault\u6839\u76EE\u5F55\uFF09", "settings.cos.local.path.placeholder": "\u4F8B\u5982\uFF1Aassets", "settings.cos.upload.path.name": "\u4E0A\u4F20\u8DEF\u5F84\u6A21\u677F", "settings.cos.upload.path.desc": "\u652F\u6301\u5360\u4F4D\u7B26\uFF1A{PATH}\uFF08\u5F53\u524D\u6587\u4EF6\u8DEF\u5F84\uFF09\u3001{FILENAME}\uFF08\u6587\u4EF6\u540D\uFF09\u3001{FOLDER}\uFF08\u6587\u4EF6\u5939\u540D\uFF09\u3001{YYYY}\uFF08\u5E74\uFF09\u3001{MM}\uFF08\u6708\uFF09\u3001{DD}\uFF08\u65E5\uFF09", "settings.cos.upload.path.placeholder": "\u4F8B\u5982\uFF1Aimages/{YYYY}/{MM}/{DD}", "settings.cos.clear.name": "\u6E05\u7A7A\u5F53\u524D\u914D\u7F6E", "settings.cos.clear.desc": "\u6E05\u7A7A\u5F53\u524D\u9009\u4E2D\u63D0\u4F9B\u5546\u7684\u6240\u6709\u914D\u7F6E\u4FE1\u606F", "settings.cos.clear.button": "\u6E05\u7A7A\u914D\u7F6E", "settings.cos.clear.success": "\u914D\u7F6E\u5DF2\u6E05\u7A7A", "settings.cos.test.name": "\u6D4B\u8BD5COS\u914D\u7F6E", "settings.cos.test.desc": "\u6D4B\u8BD5\u5F53\u524DCOS\u914D\u7F6E\u662F\u5426\u53EF\u7528", "settings.cos.test.button": "\u6D4B\u8BD5\u8FDE\u63A5", "settings.cos.test.loading": "\u6D4B\u8BD5\u4E2D...", // Notification messages "notice.settings.saved": "\u8BBE\u7F6E\u5DF2\u4FDD\u5B58", "notice.config.required": "\u8BF7\u5148\u914D\u7F6EGitHub Token\u548C\u4ED3\u5E93\u5730\u5740", "notice.url.required": "\u8BF7\u5148\u8F93\u5165GitHub\u4ED3\u5E93\u8DEF\u5F84", "notice.token.required": "\u8BF7\u5148\u586B\u5199GitHub Token", "notice.url.test.success": "URL\u683C\u5F0F\u6B63\u786E\uFF01", "notice.url.test.failed": "URL\u683C\u5F0F\u4E0D\u6B63\u786E\uFF0C\u8BF7\u68C0\u67E5\u683C\u5F0F\u3002\u8BE6\u60C5\u8BF7\u67E5\u770B\u63A7\u5236\u53F0\u3002", "notice.init.error": "\u521D\u59CB\u5316\u4ED3\u5E93\u65F6\u53D1\u751F\u9519\u8BEF", "notice.sync.error": "\u5F3A\u5236\u540C\u6B65\u65F6\u53D1\u751F\u9519\u8BEF", "notice.diagnose.result": "Vault\u4E2D\u5171\u6709 {total} \u4E2A\u6587\u4EF6\uFF0C\u5176\u4E2D {syncable} \u4E2A\u53EF\u540C\u6B65\u3002\u8BE6\u60C5\u8BF7\u67E5\u770B\u63A7\u5236\u53F0\u3002", "notice.result.with.count": "{message}\uFF0C\u5904\u7406\u4E86 {count} \u4E2A\u6587\u4EF6", "notice.cache.cleared": "\u5DF2\u6E05\u7A7A {count} \u4E2A\u6587\u4EF6\u7684\u7F13\u5B58", "notice.cache.clear.error": "\u6E05\u7A7A\u7F13\u5B58\u65F6\u53D1\u751F\u9519\u8BEF", // Sync operations "sync.success": "\u540C\u6B65\u6210\u529F: {filename}", "sync.failed": "\u540C\u6B65\u5931\u8D25: {message}", "sync.error": "\u540C\u6B65\u65F6\u53D1\u751F\u9519\u8BEF", "pull.success": "\u62C9\u53D6\u6210\u529F: {filename}", "pull.failed": "\u62C9\u53D6\u5931\u8D25: {message}", "pull.error": "\u62C9\u53D6\u65F6\u53D1\u751F\u9519\u8BEF", // Repository operations "vault.not.empty": "Vault\u4E0D\u4E3A\u7A7A\uFF0C\u65E0\u6CD5\u521D\u59CB\u5316", "repo.init.success": "\u4ED3\u5E93\u521D\u59CB\u5316\u6210\u529F", "repo.init.failed": "\u4ED3\u5E93\u521D\u59CB\u5316\u5931\u8D25: {error}", "force.sync.remote.to.local.success": "\u5F3A\u5236\u540C\u6B65\u8FDC\u7AEF\u5230\u672C\u5730\u6210\u529F", "force.sync.remote.to.local.failed": "\u5F3A\u5236\u540C\u6B65\u8FDC\u7AEF\u5230\u672C\u5730\u5931\u8D25: {error}", "no.syncable.files.in.vault": "Vault\u4E2D\u6CA1\u6709\u53EF\u540C\u6B65\u7684\u6587\u4EF6", "force.sync.local.to.remote.success.no.failures": "\u5F3A\u5236\u540C\u6B65\u672C\u5730\u5230\u8FDC\u7AEF\u6210\u529F", "force.sync.local.to.remote.success": "\u5F3A\u5236\u540C\u6B65\u672C\u5730\u5230\u8FDC\u7AEF\u5B8C\u6210\uFF0C\u6210\u529F: {processed}\uFF0C\u5931\u8D25: {failed}", "force.sync.local.to.remote.failed": "\u5F3A\u5236\u540C\u6B65\u672C\u5730\u5230\u8FDC\u7AEF\u5931\u8D25: {error}", // Actions "actions.sync.current.to.remote": "\u540C\u6B65\u5F53\u524D\u6587\u4EF6\u5230\u8FDC\u7AEF", "actions.pull.remote.to.current": "\u4ECE\u8FDC\u7AEF\u62C9\u53D6\u5230\u5F53\u524D\u6587\u4EF6", // Date "date.today": "\u4ECA\u5929", "date.yesterday": "\u6628\u5929", // GitHub API Error "github.api.rate.limit.exceeded": "GitHub API\u8C03\u7528\u6B21\u6570\u5DF2\u8FBE\u4E0A\u9650\u3002\u8BF7\u7B49\u5F85 {minutes} \u5206\u949F\u540E\u91CD\u8BD5\u3002", "github.api.rate.limit.warning": "\u26A0\uFE0F GitHub API\u8C03\u7528\u6B21\u6570\u5269\u4F59 {remaining} \u6B21\uFF0C\u8BF7\u8C28\u614E\u4F7F\u7528\u3002", "github.api.rate.limit.notice": "\u901F\u7387\u9650\u5236\u8D85\u51FA", "github.api.token.invalid": "GitHub Token\u65E0\u6548\u6216\u5DF2\u8FC7\u671F\u3002\u8BF7\u68C0\u67E5\uFF1A\n1. Token\u662F\u5426\u6B63\u786E\n2. Token\u662F\u5426\u6709\u8DB3\u591F\u7684\u6743\u9650\n3. Token\u662F\u5426\u5DF2\u8FC7\u671F", "github.api.rate.limit.hourly": "GitHub API\u8C03\u7528\u6B21\u6570\u5DF2\u8FBE\u4E0A\u9650\uFF08\u6BCF\u5C0F\u65F65000\u6B21\uFF09\u3002\n\u8BF7\u7B49\u5F85 {minutes} \u5206\u949F\u540E\u91CD\u8BD5\uFF0C\u6216\u4F7F\u7528GitHub Pro\u8D26\u53F7\u83B7\u5F97\u66F4\u9AD8\u9650\u989D\u3002", "github.api.repo.not.found": "\u4ED3\u5E93\u4E0D\u5B58\u5728\u6216\u65E0\u8BBF\u95EE\u6743\u9650\u3002\u8BF7\u68C0\u67E5\uFF1A\n1. \u4ED3\u5E93\u5730\u5740\u662F\u5426\u6B63\u786E\n2. Token\u662F\u5426\u6709\u8BBF\u95EE\u8BE5\u4ED3\u5E93\u7684\u6743\u9650\n3. \u4ED3\u5E93\u662F\u5426\u4E3A\u79C1\u6709\u4ED3\u5E93", "github.api.file.conflict": "\u6587\u4EF6\u51B2\u7A81\u3002\u8FDC\u7A0B\u6587\u4EF6\u5DF2\u88AB\u5176\u4ED6\u4EBA\u4FEE\u6539\u3002\n\u8BF7\u5148\u540C\u6B65\u8FDC\u7A0B\u66F4\u6539\uFF0C\u7136\u540E\u91CD\u8BD5\u3002", "github.api.validation.failed": "GitHub API\u9A8C\u8BC1\u5931\u8D25\u3002\u8BF7\u68C0\u67E5\uFF1A\n1. \u6587\u4EF6\u8DEF\u5F84\u662F\u5426\u6B63\u786E\n2. \u6587\u4EF6\u5185\u5BB9\u662F\u5426\u7B26\u5408\u8981\u6C42\n3. \u4ED3\u5E93\u6743\u9650\u8BBE\u7F6E", "github.api.server.error": "GitHub\u670D\u52A1\u5668\u9519\u8BEF\uFF08{status}\uFF09\u3002\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002", "github.api.network.error": "\u7F51\u7EDC\u8FDE\u63A5\u9519\u8BEF\u3002\u8BF7\u68C0\u67E5\uFF1A\n1. \u7F51\u7EDC\u8FDE\u63A5\u662F\u5426\u6B63\u5E38\n2. \u9632\u706B\u5899\u8BBE\u7F6E\n3. \u4EE3\u7406\u914D\u7F6E", "github.api.timeout.error": "\u8BF7\u6C42\u8D85\u65F6\u3002\u8BF7\u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5\u6216\u7A0D\u540E\u91CD\u8BD5\u3002", "github.api.unknown.error": "\u672A\u77E5\u9519\u8BEF\uFF1A{message}", "github.api.access.denied": "GitHub\u8BBF\u95EE\u88AB\u62D2\u7EDD\u3002\u53EF\u80FD\u539F\u56E0\uFF1A\n1. Token\u6743\u9650\u4E0D\u8DB3\n2. \u4ED3\u5E93\u4E3A\u79C1\u6709\u4E14Token\u65E0\u8BBF\u95EE\u6743\u9650\n3. \u4ED3\u5E93\u4E0D\u5B58\u5728", "github.api.resource.not.found": "\u8D44\u6E90\u672A\u627E\u5230\u3002\u8BF7\u68C0\u67E5\uFF1A\n1. \u4ED3\u5E93\u8DEF\u5F84\u662F\u5426\u6B63\u786E\n2. \u6587\u4EF6\u8DEF\u5F84\u662F\u5426\u5B58\u5728\n3. Token\u662F\u5426\u6709\u8BBF\u95EE\u8BE5\u4ED3\u5E93\u7684\u6743\u9650", "github.api.file.conflict.detailed": "\u6587\u4EF6\u51B2\u7A81\u3002\u53EF\u80FD\u539F\u56E0\uFF1A\n1. \u6587\u4EF6\u5728\u8FDC\u7A0B\u5DF2\u88AB\u4FEE\u6539\n2. \u8BF7\u5148\u4ECE\u8FDC\u7AEF\u540C\u6B65\u6700\u65B0\u7248\u672C", "github.api.invalid.request": "\u8BF7\u6C42\u53C2\u6570\u65E0\u6548\u3002\u8BF7\u68C0\u67E5\uFF1A\n1. \u6587\u4EF6\u5185\u5BB9\u662F\u5426\u8FC7\u5927\uFF08>100MB\uFF09\n2. \u6587\u4EF6\u8DEF\u5F84\u683C\u5F0F\u662F\u5426\u6B63\u786E", "github.api.server.error.detailed": "GitHub\u670D\u52A1\u5668\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002\u5982\u679C\u95EE\u9898\u6301\u7EED\u5B58\u5728\uFF0C\u8BF7\u68C0\u67E5GitHub\u670D\u52A1\u72B6\u6001\u3002", "github.api.error.with.status": "GitHub API\u9519\u8BEF ({status}): {message}", "github.api.network.failed": "\u7F51\u7EDC\u8FDE\u63A5\u5931\u8D25\u3002\u8BF7\u68C0\u67E5\uFF1A\n1. \u7F51\u7EDC\u8FDE\u63A5\u662F\u5426\u6B63\u5E38\n2. \u662F\u5426\u80FD\u8BBF\u95EEgithub.com\n3. \u9632\u706B\u5899\u6216\u4EE3\u7406\u8BBE\u7F6E", "github.api.timeout.detailed": "\u8BF7\u6C42\u8D85\u65F6\u3002\u8BF7\u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5\u6216\u7A0D\u540E\u91CD\u8BD5\u3002", "github.api.operation.failed": "\u64CD\u4F5C\u5931\u8D25: {message}", "github.api.retry.hint": "\u{1F4A1} \u63D0\u793A\uFF1A\u8FD9\u662F\u4E34\u65F6\u6027\u9519\u8BEF\uFF0C\u7A0D\u540E\u53EF\u4EE5\u91CD\u8BD5", "github.api.invalid.url.format": "\u65E0\u6548\u7684\u4ED3\u5E93URL\u683C\u5F0F", "github.api.rate.limit.exceeded.short": "GitHub API\u8C03\u7528\u6B21\u6570\u5DF2\u8FBE\u4E0A\u9650\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5", "github.api.file.upload.success": "\u6587\u4EF6\u4E0A\u4F20\u6210\u529F", "github.api.all.files.download.success": "\u6240\u6709\u6587\u4EF6\u4E0B\u8F7D\u6210\u529F", "github.api.connection.test.success": "\u2705 \u8FDE\u63A5\u6D4B\u8BD5\u6210\u529F\uFF01\n\u{1F464} \u7528\u6237: {user}\n\u{1F4C1} \u4ED3\u5E93: {repo}\n\u{1F511} \u6743\u9650: {permissions}", // Status bar "status.bar.checking": "\u68C0\u67E5\u4E2D...", "status.bar.sync": "\u540C\u6B65", "status.bar.rate.limit": "API\u9650\u5236: \u7B49\u5F85{minutes}\u5206\u949F", "status.bar.last.modified": "\u4E0A\u6B21\u66F4\u65B0: {date}", "status.bar.not.published": "\u672A\u53D1\u5E03", "status.bar.check.failed": "\u68C0\u67E5\u5931\u8D25", "status.bar.not.configured": "\u672A\u914D\u7F6E", "status.bar.local.modified": "\u672C\u5730\u5DF2\u4FEE\u6539", "status.bar.synced": "\u5DF2\u540C\u6B65", // Plugin info "plugin.name": "Git\u540C\u6B65", "command.show.sync.menu": "\u663E\u793A\u540C\u6B65\u83DC\u5355", // Test URL results "test.url.user": "\u7528\u6237", "test.url.repo": "\u4ED3\u5E93", "test.url.path": "\u8DEF\u5F84", "test.url.root": "\u6839\u76EE\u5F55", // Path info "path.info.empty": "\u8BF7\u8F93\u5165GitHub\u4ED3\u5E93\u8DEF\u5F84\u4EE5\u67E5\u770B\u540C\u6B65\u76EE\u6807", "path.info.sync.to": "\u5F53\u524D Vault \u5185\u5BB9\u5C06\u540C\u6B65\u5230 {owner}/{repo} \u4ED3\u5E93", "path.info.folder": " \u7684 {path} \u6587\u4EF6\u5939\u4E0B", "path.info.root": " \u7684\u6839\u76EE\u5F55\u4E0B", "path.info.error": "\u8DEF\u5F84\u683C\u5F0F\u4E0D\u6B63\u786E\uFF0C\u8BF7\u4F7F\u7528: https://github.com/\u7528\u6237\u540D/\u4ED3\u5E93\u540D/\u8DEF\u5F84 \u6216 \u7528\u6237\u540D/\u4ED3\u5E93\u540D/\u8DEF\u5F84", // COS upload messages "cos.upload.success": "\u56FE\u7247\u4E0A\u4F20\u6210\u529F", "cos.upload.failed": "\u56FE\u7247\u4E0A\u4F20\u5931\u8D25: {error}", "cos.upload.uploading": "\u6B63\u5728\u4E0A\u4F20\u56FE\u7247...", "cos.upload.no.config": "\u56FE\u7247\u5904\u7406\u529F\u80FD\u5DF2\u542F\u7528\uFF0C\u4F46\u9700\u8981\u914D\u7F6E\u4E91\u5B58\u50A8\u6216\u672C\u5730\u5B58\u50A8\u8DEF\u5F84", "cos.test.success": "COS\u914D\u7F6E\u6D4B\u8BD5\u6210\u529F", "cos.test.failed": "COS\u914D\u7F6E\u6D4B\u8BD5\u5931\u8D25\uFF1A{error}", "cos.error.unsupported.provider": "\u4E0D\u652F\u6301\u7684\u4E91\u5B58\u50A8\u670D\u52A1\u5546\uFF1A{provider}", "cos.error.upload.failed": "\u4E0A\u4F20\u5931\u8D25\uFF1A{error}", "cos.error.aliyun.upload.failed": "\u963F\u91CC\u4E91OSS\u4E0A\u4F20\u5931\u8D25\uFF08{status}\uFF09\uFF1A{error}", "cos.error.tencent.upload.failed": "\u817E\u8BAF\u4E91COS\u4E0A\u4F20\u5931\u8D25\uFF08{status}\uFF09\uFF1A{error}", "cos.error.aws.upload.failed": "AWS S3\u4E0A\u4F20\u5931\u8D25\uFF08{status}\uFF09\uFF1A{error}", "cos.error.cloudflare.upload.failed": "Cloudflare R2\u4E0A\u4F20\u5931\u8D25\uFF08{status}\uFF09\uFF1A{error}", "cos.error.config.invalid": "COS\u914D\u7F6E\u4E0D\u5B8C\u6574\uFF0C\u8BF7\u68C0\u67E5\u914D\u7F6E\u9879", "cos.paste.placeholder": "\u6B63\u5728\u4E0A\u4F20 {filename}..." }, en: { // Settings interface "settings.title": "Git Folder Sync Settings", "settings.language.name": "Interface Language", "settings.language.desc": "Select the display language for the plugin interface", "settings.language.auto": "Follow Obsidian", "settings.github.token.name": "GitHub Personal Token", "settings.github.token.desc": "Enter your GitHub Personal Access Token", "settings.github.token.placeholder": "ghp_xxxxxxxxxxxx", "settings.github.repo.name": "GitHub Repository Path", "settings.github.repo.desc": "Supports two formats:\n1. https://github.com/username/repo/path\n2. username/repo/path", "settings.github.repo.placeholder": "https://github.com/Xheldon/git-folder-sync/data/_post", "settings.ribbon.name": "Show plugin button in sidebar", "settings.ribbon.desc": "When enabled, display plugin button in left sidebar for quick access to settings", "settings.save.name": "Save Settings", "settings.save.desc": "Save current configuration settings", "settings.save.button": "Save Settings", "settings.diagnose.name": "Diagnose Vault Files", "settings.diagnose.desc": "Check which files in current Vault can be synchronized", "settings.diagnose.button": "Diagnose", "settings.test.url.name": "Test Repository URL", "settings.test.url.desc": "Verify if GitHub repository path format is correct", "settings.test.url.button": "Test URL", "settings.test.url.loading": "Testing...", "settings.sponsor.name": "\u{1F496} Support Developer", "settings.sponsor.desc": "If this plugin helps you, consider buying me a coffee! Your support motivates me to continue development.", "settings.sponsor.button": "\u{1F49D} PayPal Sponsor", "settings.sponsor.section.title": "Sponsor", "settings.danger.zone.title": "Danger Zone", "settings.init.name": "Initialize Repository", "settings.init.desc": "Available when Vault is empty, sync remote files to local", "settings.init.button": "Initialize Repository", "settings.init.loading": "Initializing...", "settings.sync.remote.to.local.name": "Force Sync Remote to Local", "settings.sync.remote.to.local.desc": "Sync all remote files to local Vault, existing files will be overwritten", "settings.sync.remote.to.local.button": "Force Sync to Local", "settings.sync.remote.to.local.loading": "Syncing...", "settings.sync.local.to.remote.name": "Force Sync Local to Remote", "settings.sync.local.to.remote.desc": "Sync all local Vault files to remote repository, existing files will be overwritten", "settings.sync.local.to.remote.button": "Force Sync to Remote", "settings.sync.local.to.remote.loading": "Syncing...", "settings.clear.cache.name": "Clear File Cache", "settings.clear.cache.desc": "Clear all file status cache, will fetch from GitHub on next view", "settings.clear.cache.button": "Clear Cache", // COS settings "settings.image.section.title": "Image Processing", "settings.image.enable.name": "Enable Image Processing", "settings.image.enable.desc": "When enabled, images pasted will be automatically uploaded to cloud storage and replaced with links", "settings.cos.provider.section.title": "Cloud Provider Settings", "settings.image.upload.section.title": "Image Upload Settings", "settings.cos.provider.name": "Cloud Storage Provider", "settings.cos.provider.desc": "Select the cloud object storage service to use", "settings.cos.provider.aliyun": "Aliyun OSS", "settings.cos.provider.tencent": "Tencent COS", "settings.cos.provider.aws": "AWS S3", "settings.cos.provider.cloudflare": "Cloudflare R2", "settings.cos.secret.id.name": "Access Key ID / Secret ID", "settings.cos.secret.id.desc": "Access key ID for cloud storage service", "settings.cos.secret.id.placeholder": "Enter Access Key ID or Secret ID", "settings.cos.secret.key.name": "Access Key Secret / Secret Key", "settings.cos.secret.key.desc": "Access key secret for cloud storage service", "settings.cos.secret.key.placeholder": "Enter Access Key Secret or Secret Key", "settings.cos.bucket.name": "Bucket Name", "settings.cos.bucket.desc": "Storage bucket name", "settings.cos.bucket.placeholder": "Enter bucket name", "settings.cos.endpoint.name": "Endpoint", "settings.cos.endpoint.desc": "Service endpoint address (only required for Cloudflare R2)", "settings.cos.endpoint.placeholder": "e.g.: https://accountid.r2.cloudflarestorage.com", "settings.cos.region.name": "Region", "settings.cos.region.desc": "Region setting (required for all providers)", "settings.cos.region.placeholder": "e.g.: cn-hangzhou, ap-beijing, us-east-1", "settings.cos.cdn.name": "CDN URL", "settings.cos.cdn.desc": "CDN domain for generating access links", "settings.cos.cdn.placeholder": "e.g.: https://cdn.example.com", "settings.cos.keep.local.name": "Keep Images Locally", "settings.cos.keep.local.desc": "Whether to keep a local copy of images after upload", "settings.cos.local.path.name": "Local Storage Path", "settings.cos.local.path.desc": "Directory to save images locally (relative to vault root)", "settings.cos.local.path.placeholder": "e.g.: assets", "settings.cos.upload.path.name": "Upload Path Template", "settings.cos.upload.path.desc": "Supports placeholders: {PATH} (current file path), {FILENAME} (file name), {FOLDER} (folder name), {YYYY} (year), {MM} (month), {DD} (day)", "settings.cos.upload.path.placeholder": "e.g.: images/{YYYY}/{MM}/{DD}", "settings.cos.clear.name": "Clear Current Configuration", "settings.cos.clear.desc": "Clear all configuration for the currently selected provider", "settings.cos.clear.button": "Clear Config", "settings.cos.clear.success": "Configuration cleared", "settings.cos.test.name": "Test COS Configuration", "settings.cos.test.desc": "Test if current COS configuration is available", "settings.cos.test.button": "Test Connection", "settings.cos.test.loading": "Testing...", // Notification messages "notice.settings.saved": "Settings saved", "notice.config.required": "Please configure GitHub Token and repository address first", "notice.url.required": "Please enter GitHub repository path first", "notice.token.required": "Please enter GitHub Token first", "notice.url.test.success": "URL format is correct!", "notice.url.test.failed": "URL format is incorrect, please check format. See console for details.", "notice.init.error": "Error occurred during repository initialization", "notice.sync.error": "Error occurred during force sync", "notice.diagnose.result": "Vault has {total} files in total, {syncable} can be synced. See console for details.", "notice.result.with.count": "{message}, processed {count} files", "notice.cache.cleared": "Cleared cache for {count} files", "notice.cache.clear.error": "Error occurred while clearing cache", // Sync operations "sync.success": "Sync success: {filename}", "sync.failed": "Sync failed: {message}", "sync.error": "Error occurred during sync", "pull.success": "Pull success: {filename}", "pull.failed": "Pull failed: {message}", "pull.error": "Error occurred during pull", // Repository operations "vault.not.empty": "Vault is not empty, cannot initialize", "repo.init.success": "Repository initialized successfully", "repo.init.failed": "Repository initialization failed: {error}", "force.sync.remote.to.local.success": "Force sync remote to local success", "force.sync.remote.to.local.failed": "Force sync remote to local failed: {error}", "no.syncable.files.in.vault": "No syncable files in vault", "force.sync.local.to.remote.success.no.failures": "Force sync local to remote success", "force.sync.local.to.remote.success": "Force sync local to remote completed, success: {processed}, failed: {failed}", "force.sync.local.to.remote.failed": "Force sync local to remote failed: {error}", // Actions "actions.sync.current.to.remote": "Sync current file to remote", "actions.pull.remote.to.current": "Pull remote to current file", // Date "date.today": "Today", "date.yesterday": "Yesterday", // GitHub API errors "github.api.rate.limit.exceeded": "GitHub API rate limit exceeded. Please wait {minutes} minutes before retrying.", "github.api.rate.limit.warning": "\u26A0\uFE0F GitHub API calls remaining: {remaining}. Please use carefully.", "github.api.rate.limit.notice": "Rate limit exceeded", "github.api.token.invalid": "GitHub Token is invalid or expired. Please check:\n1. Token is correct\n2. Token has sufficient permissions\n3. Token has not expired", "github.api.rate.limit.hourly": "GitHub API hourly rate limit exceeded (5000 per hour).\nPlease wait {minutes} minutes or use GitHub Pro for higher limits.", "github.api.repo.not.found": "Repository not found or no access permission. Please check:\n1. Repository URL is correct\n2. Token has access to this repository\n3. Repository is not private", "github.api.file.conflict": "File conflict. Remote file has been modified by others.\nPlease sync remote changes first, then retry.", "github.api.validation.failed": "GitHub API validation failed. Please check:\n1. File path is correct\n2. File content meets requirements\n3. Repository permission settings", "github.api.server.error": "GitHub server error ({status}). Please retry later.", "github.api.network.error": "Network connection error. Please check:\n1. Network connection is normal\n2. Firewall settings\n3. Proxy configuration", "github.api.timeout.error": "Request timeout. Please check network connection or retry later.", "github.api.unknown.error": "Unknown error: {message}", "github.api.access.denied": "GitHub access denied. Possible reasons:\n1. Insufficient token permissions\n2. Repository is private and token has no access\n3. Repository does not exist", "github.api.resource.not.found": "Resource not found. Please check:\n1. Repository path is correct\n2. File path exists\n3. Token has access to this repository", "github.api.file.conflict.detailed": "File conflict. Possible reasons:\n1. File has been modified remotely\n2. Please sync from remote first", "github.api.invalid.request": "Invalid request parameters. Please check:\n1. File content is not too large (>100MB)\n2. File path format is correct", "github.api.server.error.detailed": "GitHub server error, please retry later. If problem persists, check GitHub service status.", "github.api.error.with.status": "GitHub API error ({status}): {message}", "github.api.network.failed": "Network connection failed. Please check:\n1. Network connection is normal\n2. Can access github.com\n3. Firewall or proxy settings", "github.api.timeout.detailed": "Request timeout. Please check network connection or retry later.", "github.api.operation.failed": "Operation failed: {message}", "github.api.retry.hint": "\u{1F4A1} Tip: This is a temporary error, you can retry later", "github.api.invalid.url.format": "Invalid repository URL format", "github.api.rate.limit.exceeded.short": "GitHub API rate limit exceeded, please retry later", "github.api.file.upload.success": "File uploaded successfully", "github.api.all.files.download.success": "All files downloaded successfully", "github.api.connection.test.success": "\u2705 Connection test successful!\n\u{1F464} User: {user}\n\u{1F4C1} Repository: {repo}\n\u{1F511} Permissions: {permissions}", // Status bar "status.bar.checking": "Checking...", "status.bar.sync": "Sync", "status.bar.rate.limit": "API limit: wait {minutes} minutes", "status.bar.last.modified": "Last modified: {date}", "status.bar.not.published": "Not published", "status.bar.check.failed": "Check failed", "status.bar.not.configured": "Not configured", "status.bar.local.modified": "Local modified", "status.bar.synced": "Synced", // Plugin info "plugin.name": "Git Folder Sync", "command.show.sync.menu": "Show Sync Menu", // Test URL results "test.url.user": "User", "test.url.repo": "Repo", "test.url.path": "Path", "test.url.root": "Root", // Path info "path.info.empty": "Enter GitHub repository path to view sync target", "path.info.sync.to": "Current Vault content will sync to {owner}/{repo} repository", "path.info.folder": " under {path} folder", "path.info.root": " under root directory", "path.info.error": "Path format is incorrect, please use: https://github.com/username/repo/path or username/repo/path", // COS upload messages "cos.upload.success": "Image uploaded successfully", "cos.upload.failed": "Image upload failed: {error}", "cos.upload.uploading": "Uploading image...", "cos.upload.no.config": "Image processing is enabled, but cloud storage or local storage path needs to be configured", "cos.test.success": "COS configuration test successful", "cos.test.failed": "COS configuration test failed: {error}", "cos.error.unsupported.provider": "Unsupported cloud storage provider: {provider}", "cos.error.upload.failed": "Upload failed: {error}", "cos.error.aliyun.upload.failed": "Aliyun OSS upload failed ({status}): {error}", "cos.error.tencent.upload.failed": "Tencent COS upload failed ({status}): {error}", "cos.error.aws.upload.failed": "AWS S3 upload failed ({status}): {error}", "cos.error.cloudflare.upload.failed": "Cloudflare R2 upload failed ({status}): {error}", "cos.error.config.invalid": "COS configuration is incomplete, please check settings", "cos.paste.placeholder": "Uploading {filename}..." } }; currentLanguage = "auto"; } }); // cos-service.ts var cos_service_exports = {}; __export(cos_service_exports, { CosService: () => CosService, parseImagePath: () => parseImagePath }); function parseImagePath(template, context) { var _a; const date = context.date || new Date(); const year = date.getFullYear().toString(); const month = (date.getMonth() + 1).toString().padStart(2, "0"); const day = date.getDate().toString().padStart(2, "0"); const pathParts = context.currentFilePath.split("/"); const fileName = ((_a = pathParts.pop()) == null ? void 0 : _a.replace(/\.[^/.]+$/, "")) || ""; const folderPath = pathParts.join("/"); const folderName = pathParts[pathParts.length - 1] || ""; let result = template.replace(/\{YYYY\}/g, year).replace(/\{MM\}/g, month).replace(/\{DD\}/g, day).replace(/\{PATH\}/g, folderPath).replace(/\{FILENAME\}/g, fileName).replace(/\{FOLDER\}/g, folderName); if (!result.endsWith("/")) { result += "/"; } result += context.fileName; result = result.replace(/\/+/g, "/").replace(/^\//, ""); return result; } var import_obsidian2, CosService; var init_cos_service = __esm({ "cos-service.ts"() { init_i18n_simple(); import_obsidian2 = require("obsidian"); CosService = class { constructor(config) { this.config = config; } /** * Upload file to COS */ async uploadFile(file, remotePath) { try { switch (this.config.provider) { case "aliyun": return await this.uploadToAliyun(file, remotePath); case "tencent": return await this.uploadToTencent(file, remotePath); case "aws": return await this.uploadToAWS(file, remotePath); case "cloudflare": return await this.uploadToCloudflare(file, remotePath); default: return { success: false, message: t("cos.error.unsupported.provider", { provider: this.config.provider }) }; } } catch (error) { console.error("COS upload error:", error); return { success: false, message: t("cos.error.upload.failed", { error: error.message }) }; } } /** * Test COS configuration */ async testConnection() { try { const testContent = "test"; const testFile = new File([testContent], "test.txt", { type: "text/plain" }); const testPath = `test-${Date.now()}.txt`; const result = await this.uploadFile(testFile, testPath); if (result.success) { await this.deleteFile(testPath).catch(console.warn); return { success: true, message: t("cos.test.success") }; } return result; } catch (error) { console.error("COS test connection error:", error); return { success: false, message: t("cos.test.failed", { error: error.message }) }; } } /** * Delete file from COS */ async deleteFile(remotePath) { switch (this.config.provider) { case "aliyun": await this.deleteFromAliyun(remotePath); break; case "tencent": await this.deleteFromTencent(remotePath); break; case "aws": await this.deleteFromAWS(remotePath); break; case "cloudflare": await this.deleteFromCloudflare(remotePath); break; } } /** * Upload to Aliyun OSS */ async uploadToAliyun(file, remotePath) { const endpoint2 = `oss-${this.config.region}.aliyuncs.com`; const url = `https://${this.config.bucket}.${endpoint2}/${remotePath}`; const date = new Date().toUTCString(); const signature = await this.generateAliyunSignature("PUT", remotePath, date, file.type); const fileBuffer = await file.arrayBuffer(); const response = await (0, import_obsidian2.requestUrl)({ url, method: "PUT", headers: { "Date": date, "Content-Type": file.type, "Authorization": `OSS ${this.config.secretId}:${signature}` }, body: fileBuffer }); if (response.status >= 200 && response.status < 300) { const finalUrl = this.config.cdnUrl ? `${this.config.cdnUrl}/${remotePath}` : url; return { success: true, message: t("cos.upload.success"), url: finalUrl, key: remotePath }; } else { const errorText = response.text; return { success: false, message: t("cos.error.aliyun.upload.failed", { status: response.status, error: errorText }) }; } } /** * Upload to Tencent COS */ async uploadToTencent(file, remotePath) { const url = `https://${this.config.bucket}.cos.${this.config.region}.myqcloud.com/${remotePath}`; const date = new Date().toUTCString(); const signature = await this.generateTencentSignature("PUT", remotePath, date, file.type); const fileBuffer = await file.arrayBuffer(); const response = await (0, import_obsidian2.requestUrl)({ url, method: "PUT", headers: { "Content-Type": file.type, "Authorization": signature }, body: fileBuffer }); if (response.status >= 200 && response.status < 300) { const finalUrl = this.config.cdnUrl ? `${this.config.cdnUrl}/${remotePath}` : url; return { success: true, message: t("cos.upload.success"), url: finalUrl, key: remotePath }; } else { const errorText = response.text; return { success: false, message: t("cos.error.tencent.upload.failed", { status: response.status, error: errorText }) }; } } /** * Upload to AWS S3 */ async uploadToAWS(file, remotePath) { const url = `https://${this.config.bucket}.s3.${this.config.region}.amazonaws.com/${remotePath}`; const date = new Date(); const signature = await this.generateAWSSignature("PUT", remotePath, date, file.type); const fileBuffer = await file.arrayBuffer(); const response = await (0, import_obsidian2.requestUrl)({ url, method: "PUT", headers: { "Content-Type": file.type, ...signature.headers }, body: fileBuffer }); if (response.status >= 200 && response.status < 300) { const finalUrl = this.config.cdnUrl ? `${this.config.cdnUrl}/${remotePath}` : url; return { success: true, message: t("cos.upload.success"), url: finalUrl, key: remotePath }; } else { const errorText = response.text; return { success: false, message: t("cos.error.aws.upload.failed", { status: response.status, error: errorText }) }; } } /** * Upload to Cloudflare R2 (using S3 compatible API) */ async uploadToCloudflare(file, remotePath) { const url = `${this.config.endpoint}/${remotePath}`; const date = new Date(); const signature = await this.generateCloudflareSignature("PUT", remotePath, date, file.type); const fileBuffer = await file.arrayBuffer(); const response = await (0, import_obsidian2.requestUrl)({ url, method: "PUT", headers: { "Content-Type": file.type, ...signature.headers }, body: fileBuffer }); if (response.status >= 200 && response.status < 300) { const finalUrl = this.config.cdnUrl ? `${this.config.cdnUrl}/${remotePath}` : url; return { success: true, message: t("cos.upload.success"), url: finalUrl, key: remotePath }; } else { const errorText = response.text; return { success: false, message: t("cos.error.cloudflare.upload.failed", { status: response.status, error: errorText }) }; } } /** * Delete from Aliyun OSS */ async deleteFromAliyun(remotePath) { const endpoint2 = `oss-${this.config.region}.aliyuncs.com`; const url = `https://${this.config.bucket}.${endpoint2}/${remotePath}`; const date = new Date().toUTCString(); const signature = await this.generateAliyunSignature("DELETE", remotePath, date); await (0, import_obsidian2.requestUrl)({ url, method: "DELETE", headers: { "Date": date, "Authorization": `OSS ${this.config.secretId}:${signature}` } }); } /** * Delete from Tencent COS */ async deleteFromTencent(remotePath) { const url = `https://${this.config.bucket}.cos.${this.config.region}.myqcloud.com/${remotePath}`; const date = new Date().toUTCString(); const signature = await this.generateTencentSignature("DELETE", remotePath, date); await (0, import_obsidian2.requestUrl)({ url, method: "DELETE", headers: { "Authorization": signature } }); } /** * Delete from AWS S3 */ async deleteFromAWS(remotePath) { const url = `https://${this.config.bucket}.s3.${this.config.region}.amazonaws.com/${remotePath}`; const date = new Date(); const signature = await this.generateAWSSignature("DELETE", remotePath, date); await (0, import_obsidian2.requestUrl)({ url, method: "DELETE", headers: signature.headers }); } /** * Delete from Cloudflare R2 */ async deleteFromCloudflare(remotePath) { const url = `${this.config.endpoint}/${remotePath}`; const date = new Date(); const signature = await this.generateCloudflareSignature("DELETE", remotePath, date); await (0, import_obsidian2.requestUrl)({ url, method: "DELETE", headers: signature.headers }); } /** * Generate signature for Aliyun OSS */ async generateAliyunSignature(method, path, date, contentType) { const stringToSign = `${method} ${contentType || ""} ${date} /${this.config.bucket}/${path}`; console.log("Aliyun OSS signature debug:", { method, path, date, contentType, stringToSign: stringToSign.replace(/\n/g, "\\n"), bucket: this.config.bucket, region: this.config.region }); const encoder = new TextEncoder(); const key = await crypto.subtle.importKey( "raw", encoder.encode(this.config.secretKey), { name: "HMAC", hash: "SHA-1" }, false, ["sign"] ); const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(stringToSign)); const signatureBase64 = btoa(String.fromCharCode(...new Uint8Array(signature))); console.log("Generated Aliyun signature:", signatureBase64.substring(0, 20) + "..."); return signatureBase64; } /** * Generate signature for Tencent COS */ async generateTencentSignature(method, path, date, contentType) { const now = Math.floor(Date.now() / 1e3); const expireTime = now + 3600; const keyTime = `${now};${expireTime}`; console.log("Tencent signature debug:", { method, path, keyTime, secretId: this.config.secretId.substring(0, 8) + "...", bucket: this.config.bucket, region: this.config.region }); const signKey = await this.hmacSha1(this.config.secretKey, keyTime); const httpMethod = method.toLowerCase(); const uriPathname = `/${path}`; const httpParameters = ""; const httpHeaders = `host=${this.config.bucket}.cos.${this.config.region}.myqcloud.com`; const httpString = `${httpMethod} ${uriPathname} ${httpParameters} ${httpHeaders} `; const httpStringSha1 = await this.sha1Hash(httpString); const stringToSign = `sha1 ${keyTime} ${httpStringSha1} `; const signature = await this.hmacSha1(signKey, stringToSign); const authorization = `q-sign-algorithm=sha1&q-ak=${this.config.secretId}&q-sign-time=${keyTime}&q-key-time=${keyTime}&q-header-list=host&q-url-param-list=&q-signature=${signature}`; console.log("Generated authorization:", authorization.substring(0, 100) + "..."); return authorization; } /** * HMAC-SHA1 implementation */ async hmacSha1(key, data) { const encoder = new TextEncoder(); const keyBuffer = encoder.encode(key); const dataBuffer = encoder.encode(data); const cryptoKey = await crypto.subtle.importKey( "raw", keyBuffer, { name: "HMAC", hash: "SHA-1" }, false, ["sign"] ); const signature = await crypto.subtle.sign("HMAC", cryptoKey, dataBuffer); return Array.from(new Uint8Array(signature)).map((b) => b.toString(16).padStart(2, "0")).join(""); } /** * SHA1 hash implementation */ async sha1Hash(data) { const encoder = new TextEncoder(); const dataBuffer = encoder.encode(data); const hashBuffer = await crypto.subtle.digest("SHA-1", dataBuffer); return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join(""); } /** * SHA256 hash implementation */ async sha256Hash(data) { const encoder = new TextEncoder(); const dataBuffer = encoder.encode(data); const hashBuffer = await crypto.subtle.digest("SHA-256", dataBuffer); return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join(""); } /** * HMAC-SHA256 implementation (returns hex string) */ async hmacSha256Hex(key, data) { const encoder = new TextEncoder(); const dataBuffer = encoder.encode(data); const cryptoKey = await crypto.subtle.importKey( "raw", key, { name: "HMAC", hash: "SHA-256" }, false, ["sign"] ); const signature = await crypto.subtle.sign("HMAC", cryptoKey, dataBuffer); return Array.from(new Uint8Array(signature)).map((b) => b.toString(16).padStart(2, "0")).join(""); } /** * HMAC-SHA256 implementation (returns ArrayBuffer) */ async hmacSha256(key, data) { const encoder = new TextEncoder(); const dataBuffer = encoder.encode(data); const cryptoKey = await crypto.subtle.importKey( "raw", key, { name: "HMAC", hash: "SHA-256" }, false, ["sign"] ); return await crypto.subtle.sign("HMAC", cryptoKey, dataBuffer); } /** * Generate AWS signature key */ async getAWSSignatureKey(secretKey, dateStamp, region, service) { const encoder = new TextEncoder(); const kDate = await this.hmacSha256(encoder.encode(`AWS4${secretKey}`), dateStamp); const kRegion = await this.hmacSha256(kDate, region); const kService = await this.hmacSha256(kRegion, service); const kSigning = await this.hmacSha256(kService, "aws4_request"); return kSigning; } /** * Generate signature for AWS S3 V4 */ async generateAWSSignature(method, path, date, contentType) { const isoDate = date.toISOString().replace(/[:\-]|\.\d{3}/g, ""); const dateStamp = isoDate.substring(0, 8); const service = "s3"; const algorithm = "AWS4-HMAC-SHA256"; const host = `${this.config.bucket}.s3.${this.config.region}.amazonaws.com`; const canonicalUri = `/${path}`; const canonicalQueryString = ""; const canonicalHeaders = `host:${host} x-amz-content-sha256:UNSIGNED-PAYLOAD x-amz-date:${isoDate} `; const signedHeaders = "host;x-amz-content-sha256;x-amz-date"; const payloadHash = "UNSIGNED-PAYLOAD"; const canonicalRequest = `${method} ${canonicalUri} ${canonicalQueryString} ${canonicalHeaders} ${signedHeaders} ${payloadHash}`; const credentialScope = `${dateStamp}/${this.config.region}/${service}/aws4_request`; const canonicalRequestHash = await this.sha256Hash(canonicalRequest); const stringToSign = `${algorithm} ${isoDate} ${credentialScope} ${canonicalRequestHash}`; const signingKey = await this.getAWSSignatureKey(this.config.secretKey, dateStamp, this.config.region, service); const signature = await this.hmacSha256Hex(signingKey, stringToSign); console.log("AWS S3 signature debug:", { method, path, bucket: this.config.bucket, region: this.config.region, canonicalRequest: canonicalRequest.substring(0, 100) + "...", stringToSign: stringToSign.substring(0, 100) + "...", signature: signature.substring(0, 16) + "..." }); const headers = { "X-Amz-Date": isoDate, "X-Amz-Content-Sha256": payloadHash, "Authorization": `${algorithm} Credential=${this.config.secretId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}` }; return { headers }; } /** * Generate signature for Cloudflare R2 (S3 compatible) */ async generateCloudflareSignature(method, path, date, contentType) { const isoDate = date.toISOString().replace(/[:\-]|\.\d{3}/g, ""); const dateStamp = isoDate.substring(0, 8); const service = "s3"; const algorithm = "AWS4-HMAC-SHA256"; const region = "auto"; const host = new URL(this.config.endpoint).host; const canonicalUri = `/${path}`; const canonicalQueryString = ""; const canonicalHeaders = `host:${host} x-amz-content-sha256:UNSIGNED-PAYLOAD x-amz-date:${isoDate} `; const signedHeaders = "host;x-amz-content-sha256;x-amz-date"; const payloadHash = "UNSIGNED-PAYLOAD"; const canonicalRequest = `${method} ${canonicalUri} ${canonicalQueryString} ${canonicalHeaders} ${signedHeaders} ${payloadHash}`; const credentialScope = `${dateStamp}/${region}/${service}/aws4_request`; const canonicalRequestHash = await this.sha256Hash(canonicalRequest); const stringToSign = `${algorithm} ${isoDate} ${credentialScope} ${canonicalRequestHash}`; const signingKey = await this.getAWSSignatureKey(this.config.secretKey, dateStamp, region, service); const signature = await this.hmacSha256Hex(signingKey, stringToSign); console.log("Cloudflare R2 signature debug:", { method, path, endpoint: this.config.endpoint, host, canonicalRequest: canonicalRequest.substring(0, 100) + "...", stringToSign: stringToSign.substring(0, 100) + "...", signature: signature.substring(0, 16) + "..." }); const headers = { "X-Amz-Date": isoDate, "X-Amz-Content-Sha256": payloadHash, "Authorization": `${algorithm} Credential=${this.config.secretId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}` }; return { headers }; } }; } }); // main.ts var main_exports = {}; __export(main_exports, { default: () => GitSyncPlugin }); module.exports = __toCommonJS(main_exports); var import_obsidian3 = require("obsidian"); // types.ts var DEFAULT_SETTINGS = { githubToken: "", repositoryUrl: "", lastSyncTime: 0, showRibbonIcon: true, language: "auto", // Follow Obsidian language setting // Image processing defaults enableImageProcessing: false, // COS default settings cosProvider: "aliyun", cosConfigs: { aliyun: { secretId: "", secretKey: "", bucket: "", endpoint: "", cdnUrl: "", region: "" }, tencent: { secretId: "", secretKey: "", bucket: "", endpoint: "", cdnUrl: "", region: "" }, aws: { secretId: "", secretKey: "", bucket: "", endpoint: "", cdnUrl: "", region: "" }, cloudflare: { secretId: "", secretKey: "", bucket: "", endpoint: "", cdnUrl: "", region: "" } }, // Local image storage defaults keepLocalImages: false, localImagePath: "assets", // Image upload path template default imageUploadPath: "images/{YYYY}/{MM}/{DD}" }; // node_modules/universal-user-agent/dist-web/index.js function getUserAgent() { if (typeof navigator === "object" && "userAgent" in navigator) { return navigator.userAgent; } if (typeof process === "object" && process.version !== void 0) { return `Node.js/${process.version.substr(1)} (${process.platform}; ${process.arch})`; } return ""; } // node_modules/@octokit/core/dist-web/index.js var import_before_after_hook = __toESM(require_before_after_hook()); // node_modules/is-plain-object/dist/is-plain-object.mjs function isObject(o) { return Object.prototype.toString.call(o) === "[object Object]"; } function isPlainObject(o) { var ctor, prot; if (isObject(o) === false) return false; ctor = o.constructor; if (ctor === void 0) return true; prot = ctor.prototype; if (isObject(prot) === false) return false; if (prot.hasOwnProperty("isPrototypeOf") === false) { return false; } return true; } // node_modules/@octokit/endpoint/dist-web/index.js function lowercaseKeys(object) { if (!object) { return {}; } return Object.keys(object).reduce((newObj, key) => { newObj[key.toLowerCase()] = object[key]; return newObj; }, {}); } function mergeDeep(defaults, options) { const result = Object.assign({}, defaults); Object.keys(options).forEach((key) => { if (isPlainObject(options[key])) { if (!(key in defaults)) Object.assign(result, { [key]: options[key] }); else result[key] = mergeDeep(defaults[key], options[key]); } else { Object.assign(result, { [key]: options[key] }); } }); return result; } function removeUndefinedProperties(obj) { for (const key in obj) { if (obj[key] === void 0) { delete obj[key]; } } return obj; } function merge(defaults, route, options) { if (typeof route === "string") { let [method, url] = route.split(" "); options = Object.assign(url ? { method, url } : { url: method }, options); } else { options = Object.assign({}, route); } options.headers = lowercaseKeys(options.headers); removeUndefinedProperties(options); removeUndefinedProperties(options.headers); const mergedOptions = mergeDeep(defaults || {}, options); if (defaults && defaults.mediaType.previews.length) { mergedOptions.mediaType.previews = defaults.mediaType.previews.filter((preview) => !mergedOptions.mediaType.previews.includes(preview)).concat(mergedOptions.mediaType.previews); } mergedOptions.mediaType.previews = mergedOptions.mediaType.previews.map( (preview) => preview.replace(/-preview/, "") ); return mergedOptions; } function addQueryParameters(url, parameters) { const separator = /\?/.test(url) ? "&" : "?"; const names = Object.keys(parameters); if (names.length === 0) { return url; } return url + separator + names.map((name) => { if (name === "q") { return "q=" + parameters.q.split("+").map(encodeURIComponent).join("+"); } return `${name}=${encodeURIComponent(parameters[name])}`; }).join("&"); } var urlVariableRegex = /\{[^}]+\}/g; function removeNonChars(variableName) { return variableName.replace(/^\W+|\W+$/g, "").split(/,/); } function extractUrlVariableNames(url) { const matches = url.match(urlVariableRegex); if (!matches) { return []; } return matches.map(removeNonChars).reduce((a, b) => a.concat(b), []); } function omit(object, keysToOmit) { return Object.keys(object).filter((option) => !keysToOmit.includes(option)).reduce((obj, key) => { obj[key] = object[key]; return obj; }, {}); } function encodeReserved(str) { return str.split(/(%[0-9A-Fa-f]{2})/g).map(function(part) { if (!/%[0-9A-Fa-f]/.test(part)) { part = encodeURI(part).replace(/%5B/g, "[").replace(/%5D/g, "]"); } return part; }).join(""); } function encodeUnreserved(str) { return encodeURIComponent(str).replace(/[!'()*]/g, function(c) { return "%" + c.charCodeAt(0).toString(16).toUpperCase(); }); } function encodeValue(operator, value, key) { value = operator === "+" || operator === "#" ? encodeReserved(value) : encodeUnreserved(value); if (key) { return encodeUnreserved(key) + "=" + value; } else { return value; } } function isDefined(value) { return value !== void 0 && value !== null; } function isKeyOperator(operator) { return operator === ";" || operator === "&" || operator === "?"; } function getValues(context, operator, key, modifier) { var value = context[key], result = []; if (isDefined(value) && value !== "") { if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { value = value.toString(); if (modifier && modifier !== "*") { value = value.substring(0, parseInt(modifier, 10)); } result.push( encodeValue(operator, value, isKeyOperator(operator) ? key : "") ); } else { if (modifier === "*") { if (Array.isArray(value)) { value.filter(isDefined).forEach(function(value2) { result.push( encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value).forEach(function(k) { if (isDefined(value[k])) { result.push(encodeValue(operator, value[k], k)); } }); } } else { const tmp = []; if (Array.isArray(value)) { value.filter(isDefined).forEach(function(value2) { tmp.push(encodeValue(operator, value2)); }); } else { Object.keys(value).forEach(function(k) { if (isDefined(value[k])) { tmp.push(encodeUnreserved(k)); tmp.push(encodeValue(operator, value[k].toString())); } }); } if (isKeyOperator(operator)) { result.push(encodeUnreserved(key) + "=" + tmp.join(",")); } else if (tmp.length !== 0) { result.push(tmp.join(",")); } } } } else { if (operator === ";") { if (isDefined(value)) { result.push(encodeUnreserved(key)); } } else if (value === "" && (operator === "&" || operator === "?")) { result.push(encodeUnreserved(key) + "="); } else if (value === "") { result.push(""); } } return result; } function parseUrl(template) { return { expand: expand.bind(null, template) }; } function expand(template, context) { var operators = ["+", "#", ".", "/", ";", "?", "&"]; return template.replace( /\{([^\{\}]+)\}|([^\{\}]+)/g, function(_, expression, literal) { if (expression) { let operator = ""; const values = []; if (operators.indexOf(expression.charAt(0)) !== -1) { operator = expression.charAt(0); expression = expression.substr(1); } expression.split(/,/g).forEach(function(variable) { var tmp = /([^:\*]*)(?::(\d+)|(\*))?/.exec(variable); values.push(getValues(context, operator, tmp[1], tmp[2] || tmp[3])); }); if (operator && operator !== "+") { var separator = ","; if (operator === "?") { separator = "&"; } else if (operator !== "#") { separator = operator; } return (values.length !== 0 ? operator : "") + values.join(separator); } else { return values.join(","); } } else { return encodeReserved(literal); } } ); } function parse(options) { let method = options.method.toUpperCase(); let url = (options.url || "/").replace(/:([a-z]\w+)/g, "{$1}"); let headers = Object.assign({}, options.headers); let body; let parameters = omit(options, [ "method", "baseUrl", "url", "headers", "request", "mediaType" ]); const urlVariableNames = extractUrlVariableNames(url); url = parseUrl(url).expand(parameters); if (!/^http/.test(url)) { url = options.baseUrl + url; } const omittedParameters = Object.keys(options).filter((option) => urlVariableNames.includes(option)).concat("baseUrl"); const remainingParameters = omit(parameters, omittedParameters); const isBinaryRequest = /application\/octet-stream/i.test(headers.accept); if (!isBinaryRequest) { if (options.mediaType.format) { headers.accept = headers.accept.split(/,/).map( (preview) => preview.replace( /application\/vnd(\.\w+)(\.v3)?(\.\w+)?(\+json)?$/, `application/vnd$1$2.${options.mediaType.format}` ) ).join(","); } if (options.mediaType.previews.length) { const previewsFromAcceptHeader = headers.accept.match(/[\w-]+(?=-preview)/g) || []; headers.accept = previewsFromAcceptHeader.concat(options.mediaType.previews).map((preview) => { const format = options.mediaType.format ? `.${options.mediaType.format}` : "+json"; return `application/vnd.github.${preview}-preview${format}`; }).join(","); } } if (["GET", "HEAD"].includes(method)) { url = addQueryParameters(url, remainingParameters); } else { if ("data" in remainingParameters) { body = remainingParameters.data; } else { if (Object.keys(remainingParameters).length) { body = remainingParameters; } } } if (!headers["content-type"] && typeof body !== "undefined") { headers["content-type"] = "application/json; charset=utf-8"; } if (["PATCH", "PUT"].includes(method) && typeof body === "undefined") { body = ""; } return Object.assign( { method, url, headers }, typeof body !== "undefined" ? { body } : null, options.request ? { request: options.request } : null ); } function endpointWithDefaults(defaults, route, options) { return parse(merge(defaults, route, options)); } function withDefaults(oldDefaults, newDefaults) { const DEFAULTS2 = merge(oldDefaults, newDefaults); const endpoint2 = endpointWithDefaults.bind(null, DEFAULTS2); return Object.assign(endpoint2, { DEFAULTS: DEFAULTS2, defaults: withDefaults.bind(null, DEFAULTS2), merge: merge.bind(null, DEFAULTS2), parse }); } var VERSION = "7.0.6"; var userAgent = `octokit-endpoint.js/${VERSION} ${getUserAgent()}`; var DEFAULTS = { method: "GET", baseUrl: "https://api.github.com", headers: { accept: "application/vnd.github.v3+json", "user-agent": userAgent }, mediaType: { format: "", previews: [] } }; var endpoint = withDefaults(null, DEFAULTS); // node_modules/@octokit/request/dist-web/index.js var import_node_fetch = __toESM(require_browser()); // node_modules/deprecation/dist-web/index.js var Deprecation = class extends Error { constructor(message) { super(message); if (Error.captureStackTrace) { Error.captureStackTrace(this, this.constructor); } this.name = "Deprecation"; } }; // node_modules/@octokit/request-error/dist-web/index.js var import_once = __toESM(require_once()); var logOnceCode = (0, import_once.default)((deprecation) => console.warn(deprecation)); var logOnceHeaders = (0, import_once.default)((deprecation) => console.warn(deprecation)); var RequestError = class extends Error { constructor(message, statusCode, options) { super(message); if (Error.captureStackTrace) { Error.captureStackTrace(this, this.constructor); } this.name = "HttpError"; this.status = statusCode; let headers; if ("headers" in options && typeof options.headers !== "undefined") { headers = options.headers; } if ("response" in options) { this.response = options.response; headers = options.response.headers; } const requestCopy = Object.assign({}, options.request); if (options.request.headers.authorization) { requestCopy.headers = Object.assign({}, options.request.headers, { authorization: options.request.headers.authorization.replace(/ .*$/, " [REDACTED]") }); } requestCopy.url = requestCopy.url.replace(/\bclient_secret=\w+/g, "client_secret=[REDACTED]").replace(/\baccess_token=\w+/g, "access_token=[REDACTED]"); this.request = requestCopy; Object.defineProperty(this, "code", { get() { logOnceCode(new Deprecation("[@octokit/request-error] `error.code` is deprecated, use `error.status`.")); return statusCode; } }); Object.defineProperty(this, "headers", { get() { logOnceHeaders(new Deprecation("[@octokit/request-error] `error.headers` is deprecated, use `error.response.headers`.")); return headers || {}; } }); } }; // node_modules/@octokit/request/dist-web/index.js var VERSION2 = "6.2.8"; function getBufferResponse(response) { return response.arrayBuffer(); } function fetchWrapper(requestOptions) { const log = requestOptions.request && requestOptions.request.log ? requestOptions.request.log : console; if (isPlainObject(requestOptions.body) || Array.isArray(requestOptions.body)) { requestOptions.body = JSON.stringify(requestOptions.body); } let headers = {}; let status; let url; const fetch = requestOptions.request && requestOptions.request.fetch || globalThis.fetch || /* istanbul ignore next */ import_node_fetch.default; return fetch( requestOptions.url, Object.assign( { method: requestOptions.method, body: requestOptions.body, headers: requestOptions.headers, redirect: requestOptions.redirect, // duplex must be set if request.body is ReadableStream or Async Iterables. // See https://fetch.spec.whatwg.org/#dom-requestinit-duplex. ...requestOptions.body && { duplex: "half" } }, // `requestOptions.request.agent` type is incompatible // see https://github.com/octokit/types.ts/pull/264 requestOptions.request ) ).then(async (response) => { url = response.url; status = response.status; for (const keyAndValue of response.headers) { headers[keyAndValue[0]] = keyAndValue[1]; } if ("deprecation" in headers) { const matches = headers.link && headers.link.match(/<([^>]+)>; rel="deprecation"/); const deprecationLink = matches && matches.pop(); log.warn( `[@octokit/request] "${requestOptions.method} ${requestOptions.url}" is deprecated. It is scheduled to be removed on ${headers.sunset}${deprecationLink ? `. See ${deprecationLink}` : ""}` ); } if (status === 204 || status === 205) { return; } if (requestOptions.method === "HEAD") { if (status < 400) { return; } throw new RequestError(response.statusText, status, { response: { url, status, headers, data: void 0 }, request: requestOptions }); } if (status === 304) { throw new RequestError("Not modified", status, { response: { url, status, headers, data: await getResponseData(response) }, request: requestOptions }); } if (status >= 400) { const data = await getResponseData(response); const error = new RequestError(toErrorMessage(data), status, { response: { url, status, headers, data }, request: requestOptions }); throw error; } return getResponseData(response); }).then((data) => { return { status, url, headers, data }; }).catch((error) => { if (error instanceof RequestError) throw error; else if (error.name === "AbortError") throw error; throw new RequestError(error.message, 500, { request: requestOptions }); }); } async function getResponseData(response) { const contentType = response.headers.get("content-type"); if (/application\/json/.test(contentType)) { return response.json(); } if (!contentType || /^text\/|charset=utf-8$/.test(contentType)) { return response.text(); } return getBufferResponse(response); } function toErrorMessage(data) { if (typeof data === "string") return data; if ("message" in data) { if (Array.isArray(data.errors)) { return `${data.message}: ${data.errors.map(JSON.stringify).join(", ")}`; } return data.message; } return `Unknown error: ${JSON.stringify(data)}`; } function withDefaults2(oldEndpoint, newDefaults) { const endpoint2 = oldEndpoint.defaults(newDefaults); const newApi = function(route, parameters) { const endpointOptions = endpoint2.merge(route, parameters); if (!endpointOptions.request || !endpointOptions.request.hook) { return fetchWrapper(endpoint2.parse(endpointOptions)); } const request2 = (route2, parameters2) => { return fetchWrapper( endpoint2.parse(endpoint2.merge(route2, parameters2)) ); }; Object.assign(request2, { endpoint: endpoint2, defaults: withDefaults2.bind(null, endpoint2) }); return endpointOptions.request.hook(request2, endpointOptions); }; return Object.assign(newApi, { endpoint: endpoint2, defaults: withDefaults2.bind(null, endpoint2) }); } var request = withDefaults2(endpoint, { headers: { "user-agent": `octokit-request.js/${VERSION2} ${getUserAgent()}` } }); // node_modules/@octokit/graphql/dist-web/index.js var VERSION3 = "5.0.6"; function _buildMessageForResponseErrors(data) { return `Request failed due to following response errors: ` + data.errors.map((e) => ` - ${e.message}`).join("\n"); } var GraphqlResponseError = class extends Error { constructor(request2, headers, response) { super(_buildMessageForResponseErrors(response)); this.request = request2; this.headers = headers; this.response = response; this.name = "GraphqlResponseError"; this.errors = response.errors; this.data = response.data; if (Error.captureStackTrace) { Error.captureStackTrace(this, this.constructor); } } }; var NON_VARIABLE_OPTIONS = [ "method", "baseUrl", "url", "headers", "request", "query", "mediaType" ]; var FORBIDDEN_VARIABLE_OPTIONS = ["query", "method", "url"]; var GHES_V3_SUFFIX_REGEX = /\/api\/v3\/?$/; function graphql(request2, query, options) { if (options) { if (typeof query === "string" && "query" in options) { return Promise.reject( new Error(`[@octokit/graphql] "query" cannot be used as variable name`) ); } for (const key in options) { if (!FORBIDDEN_VARIABLE_OPTIONS.includes(key)) continue; return Promise.reject( new Error(`[@octokit/graphql] "${key}" cannot be used as variable name`) ); } } const parsedOptions = typeof query === "string" ? Object.assign({ query }, options) : query; const requestOptions = Object.keys( parsedOptions ).reduce((result, key) => { if (NON_VARIABLE_OPTIONS.includes(key)) { result[key] = parsedOptions[key]; return result; } if (!result.variables) { result.variables = {}; } result.variables[key] = parsedOptions[key]; return result; }, {}); const baseUrl = parsedOptions.baseUrl || request2.endpoint.DEFAULTS.baseUrl; if (GHES_V3_SUFFIX_REGEX.test(baseUrl)) { requestOptions.url = baseUrl.replace(GHES_V3_SUFFIX_REGEX, "/api/graphql"); } return request2(requestOptions).then((response) => { if (response.data.errors) { const headers = {}; for (const key of Object.keys(response.headers)) { headers[key] = response.headers[key]; } throw new GraphqlResponseError( requestOptions, headers, response.data ); } return response.data.data; }); } function withDefaults3(request2, newDefaults) { const newRequest = request2.defaults(newDefaults); const newApi = (query, options) => { return graphql(newRequest, query, options); }; return Object.assign(newApi, { defaults: withDefaults3.bind(null, newRequest), endpoint: newRequest.endpoint }); } var graphql2 = withDefaults3(request, { headers: { "user-agent": `octokit-graphql.js/${VERSION3} ${getUserAgent()}` }, method: "POST", url: "/graphql" }); function withCustomRequest(customRequest) { return withDefaults3(customRequest, { method: "POST", url: "/graphql" }); } // node_modules/@octokit/auth-token/dist-web/index.js var REGEX_IS_INSTALLATION_LEGACY = /^v1\./; var REGEX_IS_INSTALLATION = /^ghs_/; var REGEX_IS_USER_TO_SERVER = /^ghu_/; async function auth(token) { const isApp = token.split(/\./).length === 3; const isInstallation = REGEX_IS_INSTALLATION_LEGACY.test(token) || REGEX_IS_INSTALLATION.test(token); const isUserToServer = REGEX_IS_USER_TO_SERVER.test(token); const tokenType = isApp ? "app" : isInstallation ? "installation" : isUserToServer ? "user-to-server" : "oauth"; return { type: "token", token, tokenType }; } function withAuthorizationPrefix(token) { if (token.split(/\./).length === 3) { return `bearer ${token}`; } return `token ${token}`; } async function hook(token, request2, route, parameters) { const endpoint2 = request2.endpoint.merge( route, parameters ); endpoint2.headers.authorization = withAuthorizationPrefix(token); return request2(endpoint2); } var createTokenAuth = function createTokenAuth2(token) { if (!token) { throw new Error("[@octokit/auth-token] No token passed to createTokenAuth"); } if (typeof token !== "string") { throw new Error( "[@octokit/auth-token] Token passed to createTokenAuth is not a string" ); } token = token.replace(/^(token|bearer) +/i, ""); return Object.assign(auth.bind(null, token), { hook: hook.bind(null, token) }); }; // node_modules/@octokit/core/dist-web/index.js var VERSION4 = "4.2.4"; var Octokit = class { static defaults(defaults) { const OctokitWithDefaults = class extends this { constructor(...args) { const options = args[0] || {}; if (typeof defaults === "function") { super(defaults(options)); return; } super( Object.assign( {}, defaults, options, options.userAgent && defaults.userAgent ? { userAgent: `${options.userAgent} ${defaults.userAgent}` } : null ) ); } }; return OctokitWithDefaults; } /** * Attach a plugin (or many) to your Octokit instance. * * @example * const API = Octokit.plugin(plugin1, plugin2, plugin3, ...) */ static plugin(...newPlugins) { var _a; const currentPlugins = this.plugins; const NewOctokit = (_a = class extends this { }, _a.plugins = currentPlugins.concat( newPlugins.filter((plugin) => !currentPlugins.includes(plugin)) ), _a); return NewOctokit; } constructor(options = {}) { const hook2 = new import_before_after_hook.Collection(); const requestDefaults = { baseUrl: request.endpoint.DEFAULTS.baseUrl, headers: {}, request: Object.assign({}, options.request, { // @ts-ignore internal usage only, no need to type hook: hook2.bind(null, "request") }), mediaType: { previews: [], format: "" } }; requestDefaults.headers["user-agent"] = [ options.userAgent, `octokit-core.js/${VERSION4} ${getUserAgent()}` ].filter(Boolean).join(" "); if (options.baseUrl) { requestDefaults.baseUrl = options.baseUrl; } if (options.previews) { requestDefaults.mediaType.previews = options.previews; } if (options.timeZone) { requestDefaults.headers["time-zone"] = options.timeZone; } this.request = request.defaults(requestDefaults); this.graphql = withCustomRequest(this.request).defaults(requestDefaults); this.log = Object.assign( { debug: () => { }, info: () => { }, warn: console.warn.bind(console), error: console.error.bind(console) }, options.log ); this.hook = hook2; if (!options.authStrategy) { if (!options.auth) { this.auth = async () => ({ type: "unauthenticated" }); } else { const auth2 = createTokenAuth(options.auth); hook2.wrap("request", auth2.hook); this.auth = auth2; } } else { const { authStrategy, ...otherOptions } = options; const auth2 = authStrategy( Object.assign( { request: this.request, log: this.log, // we pass the current octokit instance as well as its constructor options // to allow for authentication strategies that return a new octokit instance // that shares the same internal state as the current one. The original // requirement for this was the "event-octokit" authentication strategy // of https://github.com/probot/octokit-auth-probot. octokit: this, octokitOptions: otherOptions }, options.auth ) ); hook2.wrap("request", auth2.hook); this.auth = auth2; } const classConstructor = this.constructor; classConstructor.plugins.forEach((plugin) => { Object.assign(this, plugin(this, options)); }); } }; Octokit.VERSION = VERSION4; Octokit.plugins = []; // node_modules/@octokit/plugin-request-log/dist-web/index.js var VERSION5 = "1.0.4"; function requestLog(octokit) { octokit.hook.wrap("request", (request2, options) => { octokit.log.debug("request", options); const start = Date.now(); const requestOptions = octokit.request.endpoint.parse(options); const path = requestOptions.url.replace(options.baseUrl, ""); return request2(options).then((response) => { octokit.log.info(`${requestOptions.method} ${path} - ${response.status} in ${Date.now() - start}ms`); return response; }).catch((error) => { octokit.log.info(`${requestOptions.method} ${path} - ${error.status} in ${Date.now() - start}ms`); throw error; }); }); } requestLog.VERSION = VERSION5; // node_modules/@octokit/plugin-paginate-rest/dist-web/index.js var VERSION6 = "6.1.2"; function normalizePaginatedListResponse(response) { if (!response.data) { return { ...response, data: [] }; } const responseNeedsNormalization = "total_count" in response.data && !("url" in response.data); if (!responseNeedsNormalization) return response; const incompleteResults = response.data.incomplete_results; const repositorySelection = response.data.repository_selection; const totalCount = response.data.total_count; delete response.data.incomplete_results; delete response.data.repository_selection; delete response.data.total_count; const namespaceKey = Object.keys(response.data)[0]; const data = response.data[namespaceKey]; response.data = data; if (typeof incompleteResults !== "undefined") { response.data.incomplete_results = incompleteResults; } if (typeof repositorySelection !== "undefined") { response.data.repository_selection = repositorySelection; } response.data.total_count = totalCount; return response; } function iterator(octokit, route, parameters) { const options = typeof route === "function" ? route.endpoint(parameters) : octokit.request.endpoint(route, parameters); const requestMethod = typeof route === "function" ? route : octokit.request; const method = options.method; const headers = options.headers; let url = options.url; return { [Symbol.asyncIterator]: () => ({ async next() { if (!url) return { done: true }; try { const response = await requestMethod({ method, url, headers }); const normalizedResponse = normalizePaginatedListResponse(response); url = ((normalizedResponse.headers.link || "").match( /<([^>]+)>;\s*rel="next"/ ) || [])[1]; return { value: normalizedResponse }; } catch (error) { if (error.status !== 409) throw error; url = ""; return { value: { status: 200, headers: {}, data: [] } }; } } }) }; } function paginate(octokit, route, parameters, mapFn) { if (typeof parameters === "function") { mapFn = parameters; parameters = void 0; } return gather( octokit, [], iterator(octokit, route, parameters)[Symbol.asyncIterator](), mapFn ); } function gather(octokit, results, iterator2, mapFn) { return iterator2.next().then((result) => { if (result.done) { return results; } let earlyExit = false; function done() { earlyExit = true; } results = results.concat( mapFn ? mapFn(result.value, done) : result.value.data ); if (earlyExit) { return results; } return gather(octokit, results, iterator2, mapFn); }); } var composePaginateRest = Object.assign(paginate, { iterator }); function paginateRest(octokit) { return { paginate: Object.assign(paginate.bind(null, octokit), { iterator: iterator.bind(null, octokit) }) }; } paginateRest.VERSION = VERSION6; // node_modules/@octokit/plugin-rest-endpoint-methods/dist-web/index.js var VERSION7 = "7.2.3"; var Endpoints = { actions: { addCustomLabelsToSelfHostedRunnerForOrg: [ "POST /orgs/{org}/actions/runners/{runner_id}/labels" ], addCustomLabelsToSelfHostedRunnerForRepo: [ "POST /repos/{owner}/{repo}/actions/runners/{runner_id}/labels" ], addSelectedRepoToOrgSecret: [ "PUT /orgs/{org}/actions/secrets/{secret_name}/repositories/{repository_id}" ], addSelectedRepoToOrgVariable: [ "PUT /orgs/{org}/actions/variables/{name}/repositories/{repository_id}" ], addSelectedRepoToRequiredWorkflow: [ "PUT /orgs/{org}/actions/required_workflows/{required_workflow_id}/repositories/{repository_id}" ], approveWorkflowRun: [ "POST /repos/{owner}/{repo}/actions/runs/{run_id}/approve" ], cancelWorkflowRun: [ "POST /repos/{owner}/{repo}/actions/runs/{run_id}/cancel" ], createEnvironmentVariable: [ "POST /repositories/{repository_id}/environments/{environment_name}/variables" ], createOrUpdateEnvironmentSecret: [ "PUT /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name}" ], createOrUpdateOrgSecret: ["PUT /orgs/{org}/actions/secrets/{secret_name}"], createOrUpdateRepoSecret: [ "PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}" ], createOrgVariable: ["POST /orgs/{org}/actions/variables"], createRegistrationTokenForOrg: [ "POST /orgs/{org}/actions/runners/registration-token" ], createRegistrationTokenForRepo: [ "POST /repos/{owner}/{repo}/actions/runners/registration-token" ], createRemoveTokenForOrg: ["POST /orgs/{org}/actions/runners/remove-token"], createRemoveTokenForRepo: [ "POST /repos/{owner}/{repo}/actions/runners/remove-token" ], createRepoVariable: ["POST /repos/{owner}/{repo}/actions/variables"], createRequiredWorkflow: ["POST /orgs/{org}/actions/required_workflows"], createWorkflowDispatch: [ "POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches" ], deleteActionsCacheById: [ "DELETE /repos/{owner}/{repo}/actions/caches/{cache_id}" ], deleteActionsCacheByKey: [ "DELETE /repos/{owner}/{repo}/actions/caches{?key,ref}" ], deleteArtifact: [ "DELETE /repos/{owner}/{repo}/actions/artifacts/{artifact_id}" ], deleteEnvironmentSecret: [ "DELETE /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name}" ], deleteEnvironmentVariable: [ "DELETE /repositories/{repository_id}/environments/{environment_name}/variables/{name}" ], deleteOrgSecret: ["DELETE /orgs/{org}/actions/secrets/{secret_name}"], deleteOrgVariable: ["DELETE /orgs/{org}/actions/variables/{name}"], deleteRepoSecret: [ "DELETE /repos/{owner}/{repo}/actions/secrets/{secret_name}" ], deleteRepoVariable: [ "DELETE /repos/{owner}/{repo}/actions/variables/{name}" ], deleteRequiredWorkflow: [ "DELETE /orgs/{org}/actions/required_workflows/{required_workflow_id}" ], deleteSelfHostedRunnerFromOrg: [ "DELETE /orgs/{org}/actions/runners/{runner_id}" ], deleteSelfHostedRunnerFromRepo: [ "DELETE /repos/{owner}/{repo}/actions/runners/{runner_id}" ], deleteWorkflowRun: ["DELETE /repos/{owner}/{repo}/actions/runs/{run_id}"], deleteWorkflowRunLogs: [ "DELETE /repos/{owner}/{repo}/actions/runs/{run_id}/logs" ], disableSelectedRepositoryGithubActionsOrganization: [ "DELETE /orgs/{org}/actions/permissions/repositories/{repository_id}" ], disableWorkflow: [ "PUT /repos/{owner}/{repo}/actions/workflows/{workflow_id}/disable" ], downloadArtifact: [ "GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id}/{archive_format}" ], downloadJobLogsForWorkflowRun: [ "GET /repos/{owner}/{repo}/actions/jobs/{job_id}/logs" ], downloadWorkflowRunAttemptLogs: [ "GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}/logs" ], downloadWorkflowRunLogs: [ "GET /repos/{owner}/{repo}/actions/runs/{run_id}/logs" ], enableSelectedRepositoryGithubActionsOrganization: [ "PUT /orgs/{org}/actions/permissions/repositories/{repository_id}" ], enableWorkflow: [ "PUT /repos/{owner}/{repo}/actions/workflows/{workflow_id}/enable" ], generateRunnerJitconfigForOrg: [ "POST /orgs/{org}/actions/runners/generate-jitconfig" ], generateRunnerJitconfigForRepo: [ "POST /repos/{owner}/{repo}/actions/runners/generate-jitconfig" ], getActionsCacheList: ["GET /repos/{owner}/{repo}/actions/caches"], getActionsCacheUsage: ["GET /repos/{owner}/{repo}/actions/cache/usage"], getActionsCacheUsageByRepoForOrg: [ "GET /orgs/{org}/actions/cache/usage-by-repository" ], getActionsCacheUsageForOrg: ["GET /orgs/{org}/actions/cache/usage"], getAllowedActionsOrganization: [ "GET /orgs/{org}/actions/permissions/selected-actions" ], getAllowedActionsRepository: [ "GET /repos/{owner}/{repo}/actions/permissions/selected-actions" ], getArtifact: ["GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id}"], getEnvironmentPublicKey: [ "GET /repositories/{repository_id}/environments/{environment_name}/secrets/public-key" ], getEnvironmentSecret: [ "GET /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name}" ], getEnvironmentVariable: [ "GET /repositories/{repository_id}/environments/{environment_name}/variables/{name}" ], getGithubActionsDefaultWorkflowPermissionsOrganization: [ "GET /orgs/{org}/actions/permissions/workflow" ], getGithubActionsDefaultWorkflowPermissionsRepository: [ "GET /repos/{owner}/{repo}/actions/permissions/workflow" ], getGithubActionsPermissionsOrganization: [ "GET /orgs/{org}/actions/permissions" ], getGithubActionsPermissionsRepository: [ "GET /repos/{owner}/{repo}/actions/permissions" ], getJobForWorkflowRun: ["GET /repos/{owner}/{repo}/actions/jobs/{job_id}"], getOrgPublicKey: ["GET /orgs/{org}/actions/secrets/public-key"], getOrgSecret: ["GET /orgs/{org}/actions/secrets/{secret_name}"], getOrgVariable: ["GET /orgs/{org}/actions/variables/{name}"], getPendingDeploymentsForRun: [ "GET /repos/{owner}/{repo}/actions/runs/{run_id}/pending_deployments" ], getRepoPermissions: [ "GET /repos/{owner}/{repo}/actions/permissions", {}, { renamed: ["actions", "getGithubActionsPermissionsRepository"] } ], getRepoPublicKey: ["GET /repos/{owner}/{repo}/actions/secrets/public-key"], getRepoRequiredWorkflow: [ "GET /repos/{org}/{repo}/actions/required_workflows/{required_workflow_id_for_repo}" ], getRepoRequiredWorkflowUsage: [ "GET /repos/{org}/{repo}/actions/required_workflows/{required_workflow_id_for_repo}/timing" ], getRepoSecret: ["GET /repos/{owner}/{repo}/actions/secrets/{secret_name}"], getRepoVariable: ["GET /repos/{owner}/{repo}/actions/variables/{name}"], getRequiredWorkflow: [ "GET /orgs/{org}/actions/required_workflows/{required_workflow_id}" ], getReviewsForRun: [ "GET /repos/{owner}/{repo}/actions/runs/{run_id}/approvals" ], getSelfHostedRunnerForOrg: ["GET /orgs/{org}/actions/runners/{runner_id}"], getSelfHostedRunnerForRepo: [ "GET /repos/{owner}/{repo}/actions/runners/{runner_id}" ], getWorkflow: ["GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}"], getWorkflowAccessToRepository: [ "GET /repos/{owner}/{repo}/actions/permissions/access" ], getWorkflowRun: ["GET /repos/{owner}/{repo}/actions/runs/{run_id}"], getWorkflowRunAttempt: [ "GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}" ], getWorkflowRunUsage: [ "GET /repos/{owner}/{repo}/actions/runs/{run_id}/timing" ], getWorkflowUsage: [ "GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/timing" ], listArtifactsForRepo: ["GET /repos/{owner}/{repo}/actions/artifacts"], listEnvironmentSecrets: [ "GET /repositories/{repository_id}/environments/{environment_name}/secrets" ], listEnvironmentVariables: [ "GET /repositories/{repository_id}/environments/{environment_name}/variables" ], listJobsForWorkflowRun: [ "GET /repos/{owner}/{repo}/actions/runs/{run_id}/jobs" ], listJobsForWorkflowRunAttempt: [ "GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt_number}/jobs" ], listLabelsForSelfHostedRunnerForOrg: [ "GET /orgs/{org}/actions/runners/{runner_id}/labels" ], listLabelsForSelfHostedRunnerForRepo: [ "GET /repos/{owner}/{repo}/actions/runners/{runner_id}/labels" ], listOrgSecrets: ["GET /orgs/{org}/actions/secrets"], listOrgVariables: ["GET /orgs/{org}/actions/variables"], listRepoOrganizationSecrets: [ "GET /repos/{owner}/{repo}/actions/organization-secrets" ], listRepoOrganizationVariables: [ "GET /repos/{owner}/{repo}/actions/organization-variables" ], listRepoRequiredWorkflows: [ "GET /repos/{org}/{repo}/actions/required_workflows" ], listRepoSecrets: ["GET /repos/{owner}/{repo}/actions/secrets"], listRepoVariables: ["GET /repos/{owner}/{repo}/actions/variables"], listRepoWorkflows: ["GET /repos/{owner}/{repo}/actions/workflows"], listRequiredWorkflowRuns: [ "GET /repos/{owner}/{repo}/actions/required_workflows/{required_workflow_id_for_repo}/runs" ], listRequiredWorkflows: ["GET /orgs/{org}/actions/required_workflows"], listRunnerApplicationsForOrg: ["GET /orgs/{org}/actions/runners/downloads"], listRunnerApplicationsForRepo: [ "GET /repos/{owner}/{repo}/actions/runners/downloads" ], listSelectedReposForOrgSecret: [ "GET /orgs/{org}/actions/secrets/{secret_name}/repositories" ], listSelectedReposForOrgVariable: [ "GET /orgs/{org}/actions/variables/{name}/repositories" ], listSelectedRepositoriesEnabledGithubActionsOrganization: [ "GET /orgs/{org}/actions/permissions/repositories" ], listSelectedRepositoriesRequiredWorkflow: [ "GET /orgs/{org}/actions/required_workflows/{required_workflow_id}/repositories" ], listSelfHostedRunnersForOrg: ["GET /orgs/{org}/actions/runners"], listSelfHostedRunnersForRepo: ["GET /repos/{owner}/{repo}/actions/runners"], listWorkflowRunArtifacts: [ "GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts" ], listWorkflowRuns: [ "GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs" ], listWorkflowRunsForRepo: ["GET /repos/{owner}/{repo}/actions/runs"], reRunJobForWorkflowRun: [ "POST /repos/{owner}/{repo}/actions/jobs/{job_id}/rerun" ], reRunWorkflow: ["POST /repos/{owner}/{repo}/actions/runs/{run_id}/rerun"], reRunWorkflowFailedJobs: [ "POST /repos/{owner}/{repo}/actions/runs/{run_id}/rerun-failed-jobs" ], removeAllCustomLabelsFromSelfHostedRunnerForOrg: [ "DELETE /orgs/{org}/actions/runners/{runner_id}/labels" ], removeAllCustomLabelsFromSelfHostedRunnerForRepo: [ "DELETE /repos/{owner}/{repo}/actions/runners/{runner_id}/labels" ], removeCustomLabelFromSelfHostedRunnerForOrg: [ "DELETE /orgs/{org}/actions/runners/{runner_id}/labels/{name}" ], removeCustomLabelFromSelfHostedRunnerForRepo: [ "DELETE /repos/{owner}/{repo}/actions/runners/{runner_id}/labels/{name}" ], removeSelectedRepoFromOrgSecret: [ "DELETE /orgs/{org}/actions/secrets/{secret_name}/repositories/{repository_id}" ], removeSelectedRepoFromOrgVariable: [ "DELETE /orgs/{org}/actions/variables/{name}/repositories/{repository_id}" ], removeSelectedRepoFromRequiredWorkflow: [ "DELETE /orgs/{org}/actions/required_workflows/{required_workflow_id}/repositories/{repository_id}" ], reviewCustomGatesForRun: [ "POST /repos/{owner}/{repo}/actions/runs/{run_id}/deployment_protection_rule" ], reviewPendingDeploymentsForRun: [ "POST /repos/{owner}/{repo}/actions/runs/{run_id}/pending_deployments" ], setAllowedActionsOrganization: [ "PUT /orgs/{org}/actions/permissions/selected-actions" ], setAllowedActionsRepository: [ "PUT /repos/{owner}/{repo}/actions/permissions/selected-actions" ], setCustomLabelsForSelfHostedRunnerForOrg: [ "PUT /orgs/{org}/actions/runners/{runner_id}/labels" ], setCustomLabelsForSelfHostedRunnerForRepo: [ "PUT /repos/{owner}/{repo}/actions/runners/{runner_id}/labels" ], setGithubActionsDefaultWorkflowPermissionsOrganization: [ "PUT /orgs/{org}/actions/permissions/workflow" ], setGithubActionsDefaultWorkflowPermissionsRepository: [ "PUT /repos/{owner}/{repo}/actions/permissions/workflow" ], setGithubActionsPermissionsOrganization: [ "PUT /orgs/{org}/actions/permissions" ], setGithubActionsPermissionsRepository: [ "PUT /repos/{owner}/{repo}/actions/permissions" ], setSelectedReposForOrgSecret: [ "PUT /orgs/{org}/actions/secrets/{secret_name}/repositories" ], setSelectedReposForOrgVariable: [ "PUT /orgs/{org}/actions/variables/{name}/repositories" ], setSelectedReposToRequiredWorkflow: [ "PUT /orgs/{org}/actions/required_workflows/{required_workflow_id}/repositories" ], setSelectedRepositoriesEnabledGithubActionsOrganization: [ "PUT /orgs/{org}/actions/permissions/repositories" ], setWorkflowAccessToRepository: [ "PUT /repos/{owner}/{repo}/actions/permissions/access" ], updateEnvironmentVariable: [ "PATCH /repositories/{repository_id}/environments/{environment_name}/variables/{name}" ], updateOrgVariable: ["PATCH /orgs/{org}/actions/variables/{name}"], updateRepoVariable: [ "PATCH /repos/{owner}/{repo}/actions/variables/{name}" ], updateRequiredWorkflow: [ "PATCH /orgs/{org}/actions/required_workflows/{required_workflow_id}" ] }, activity: { checkRepoIsStarredByAuthenticatedUser: ["GET /user/starred/{owner}/{repo}"], deleteRepoSubscription: ["DELETE /repos/{owner}/{repo}/subscription"], deleteThreadSubscription: [ "DELETE /notifications/threads/{thread_id}/subscription" ], getFeeds: ["GET /feeds"], getRepoSubscription: ["GET /repos/{owner}/{repo}/subscription"], getThread: ["GET /notifications/threads/{thread_id}"], getThreadSubscriptionForAuthenticatedUser: [ "GET /notifications/threads/{thread_id}/subscription" ], listEventsForAuthenticatedUser: ["GET /users/{username}/events"], listNotificationsForAuthenticatedUser: ["GET /notifications"], listOrgEventsForAuthenticatedUser: [ "GET /users/{username}/events/orgs/{org}" ], listPublicEvents: ["GET /events"], listPublicEventsForRepoNetwork: ["GET /networks/{owner}/{repo}/events"], listPublicEventsForUser: ["GET /users/{username}/events/public"], listPublicOrgEvents: ["GET /orgs/{org}/events"], listReceivedEventsForUser: ["GET /users/{username}/received_events"], listReceivedPublicEventsForUser: [ "GET /users/{username}/received_events/public" ], listRepoEvents: ["GET /repos/{owner}/{repo}/events"], listRepoNotificationsForAuthenticatedUser: [ "GET /repos/{owner}/{repo}/notifications" ], listReposStarredByAuthenticatedUser: ["GET /user/starred"], listReposStarredByUser: ["GET /users/{username}/starred"], listReposWatchedByUser: ["GET /users/{username}/subscriptions"], listStargazersForRepo: ["GET /repos/{owner}/{repo}/stargazers"], listWatchedReposForAuthenticatedUser: ["GET /user/subscriptions"], listWatchersForRepo: ["GET /repos/{owner}/{repo}/subscribers"], markNotificationsAsRead: ["PUT /notifications"], markRepoNotificationsAsRead: ["PUT /repos/{owner}/{repo}/notifications"], markThreadAsRead: ["PATCH /notifications/threads/{thread_id}"], setRepoSubscription: ["PUT /repos/{owner}/{repo}/subscription"], setThreadSubscription: [ "PUT /notifications/threads/{thread_id}/subscription" ], starRepoForAuthenticatedUser: ["PUT /user/starred/{owner}/{repo}"], unstarRepoForAuthenticatedUser: ["DELETE /user/starred/{owner}/{repo}"] }, apps: { addRepoToInstallation: [ "PUT /user/installations/{installation_id}/repositories/{repository_id}", {}, { renamed: ["apps", "addRepoToInstallationForAuthenticatedUser"] } ], addRepoToInstallationForAuthenticatedUser: [ "PUT /user/installations/{installation_id}/repositories/{repository_id}" ], checkToken: ["POST /applications/{client_id}/token"], createFromManifest: ["POST /app-manifests/{code}/conversions"], createInstallationAccessToken: [ "POST /app/installations/{installation_id}/access_tokens" ], deleteAuthorization: ["DELETE /applications/{client_id}/grant"], deleteInstallation: ["DELETE /app/installations/{installation_id}"], deleteToken: ["DELETE /applications/{client_id}/token"], getAuthenticated: ["GET /app"], getBySlug: ["GET /apps/{app_slug}"], getInstallation: ["GET /app/installations/{installation_id}"], getOrgInstallation: ["GET /orgs/{org}/installation"], getRepoInstallation: ["GET /repos/{owner}/{repo}/installation"], getSubscriptionPlanForAccount: [ "GET /marketplace_listing/accounts/{account_id}" ], getSubscriptionPlanForAccountStubbed: [ "GET /marketplace_listing/stubbed/accounts/{account_id}" ], getUserInstallation: ["GET /users/{username}/installation"], getWebhookConfigForApp: ["GET /app/hook/config"], getWebhookDelivery: ["GET /app/hook/deliveries/{delivery_id}"], listAccountsForPlan: ["GET /marketplace_listing/plans/{plan_id}/accounts"], listAccountsForPlanStubbed: [ "GET /marketplace_listing/stubbed/plans/{plan_id}/accounts" ], listInstallationReposForAuthenticatedUser: [ "GET /user/installations/{installation_id}/repositories" ], listInstallationRequestsForAuthenticatedApp: [ "GET /app/installation-requests" ], listInstallations: ["GET /app/installations"], listInstallationsForAuthenticatedUser: ["GET /user/installations"], listPlans: ["GET /marketplace_listing/plans"], listPlansStubbed: ["GET /marketplace_listing/stubbed/plans"], listReposAccessibleToInstallation: ["GET /installation/repositories"], listSubscriptionsForAuthenticatedUser: ["GET /user/marketplace_purchases"], listSubscriptionsForAuthenticatedUserStubbed: [ "GET /user/marketplace_purchases/stubbed" ], listWebhookDeliveries: ["GET /app/hook/deliveries"], redeliverWebhookDelivery: [ "POST /app/hook/deliveries/{delivery_id}/attempts" ], removeRepoFromInstallation: [ "DELETE /user/installations/{installation_id}/repositories/{repository_id}", {}, { renamed: ["apps", "removeRepoFromInstallationForAuthenticatedUser"] } ], removeRepoFromInstallationForAuthenticatedUser: [ "DELETE /user/installations/{installation_id}/repositories/{repository_id}" ], resetToken: ["PATCH /applications/{client_id}/token"], revokeInstallationAccessToken: ["DELETE /installation/token"], scopeToken: ["POST /applications/{client_id}/token/scoped"], suspendInstallation: ["PUT /app/installations/{installation_id}/suspended"], unsuspendInstallation: [ "DELETE /app/installations/{installation_id}/suspended" ], updateWebhookConfigForApp: ["PATCH /app/hook/config"] }, billing: { getGithubActionsBillingOrg: ["GET /orgs/{org}/settings/billing/actions"], getGithubActionsBillingUser: [ "GET /users/{username}/settings/billing/actions" ], getGithubPackagesBillingOrg: ["GET /orgs/{org}/settings/billing/packages"], getGithubPackagesBillingUser: [ "GET /users/{username}/settings/billing/packages" ], getSharedStorageBillingOrg: [ "GET /orgs/{org}/settings/billing/shared-storage" ], getSharedStorageBillingUser: [ "GET /users/{username}/settings/billing/shared-storage" ] }, checks: { create: ["POST /repos/{owner}/{repo}/check-runs"], createSuite: ["POST /repos/{owner}/{repo}/check-suites"], get: ["GET /repos/{owner}/{repo}/check-runs/{check_run_id}"], getSuite: ["GET /repos/{owner}/{repo}/check-suites/{check_suite_id}"], listAnnotations: [ "GET /repos/{owner}/{repo}/check-runs/{check_run_id}/annotations" ], listForRef: ["GET /repos/{owner}/{repo}/commits/{ref}/check-runs"], listForSuite: [ "GET /repos/{owner}/{repo}/check-suites/{check_suite_id}/check-runs" ], listSuitesForRef: ["GET /repos/{owner}/{repo}/commits/{ref}/check-suites"], rerequestRun: [ "POST /repos/{owner}/{repo}/check-runs/{check_run_id}/rerequest" ], rerequestSuite: [ "POST /repos/{owner}/{repo}/check-suites/{check_suite_id}/rerequest" ], setSuitesPreferences: [ "PATCH /repos/{owner}/{repo}/check-suites/preferences" ], update: ["PATCH /repos/{owner}/{repo}/check-runs/{check_run_id}"] }, codeScanning: { deleteAnalysis: [ "DELETE /repos/{owner}/{repo}/code-scanning/analyses/{analysis_id}{?confirm_delete}" ], getAlert: [ "GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}", {}, { renamedParameters: { alert_id: "alert_number" } } ], getAnalysis: [ "GET /repos/{owner}/{repo}/code-scanning/analyses/{analysis_id}" ], getCodeqlDatabase: [ "GET /repos/{owner}/{repo}/code-scanning/codeql/databases/{language}" ], getDefaultSetup: ["GET /repos/{owner}/{repo}/code-scanning/default-setup"], getSarif: ["GET /repos/{owner}/{repo}/code-scanning/sarifs/{sarif_id}"], listAlertInstances: [ "GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/instances" ], listAlertsForOrg: ["GET /orgs/{org}/code-scanning/alerts"], listAlertsForRepo: ["GET /repos/{owner}/{repo}/code-scanning/alerts"], listAlertsInstances: [ "GET /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}/instances", {}, { renamed: ["codeScanning", "listAlertInstances"] } ], listCodeqlDatabases: [ "GET /repos/{owner}/{repo}/code-scanning/codeql/databases" ], listRecentAnalyses: ["GET /repos/{owner}/{repo}/code-scanning/analyses"], updateAlert: [ "PATCH /repos/{owner}/{repo}/code-scanning/alerts/{alert_number}" ], updateDefaultSetup: [ "PATCH /repos/{owner}/{repo}/code-scanning/default-setup" ], uploadSarif: ["POST /repos/{owner}/{repo}/code-scanning/sarifs"] }, codesOfConduct: { getAllCodesOfConduct: ["GET /codes_of_conduct"], getConductCode: ["GET /codes_of_conduct/{key}"] }, codespaces: { addRepositoryForSecretForAuthenticatedUser: [ "PUT /user/codespaces/secrets/{secret_name}/repositories/{repository_id}" ], addSelectedRepoToOrgSecret: [ "PUT /orgs/{org}/codespaces/secrets/{secret_name}/repositories/{repository_id}" ], codespaceMachinesForAuthenticatedUser: [ "GET /user/codespaces/{codespace_name}/machines" ], createForAuthenticatedUser: ["POST /user/codespaces"], createOrUpdateOrgSecret: [ "PUT /orgs/{org}/codespaces/secrets/{secret_name}" ], createOrUpdateRepoSecret: [ "PUT /repos/{owner}/{repo}/codespaces/secrets/{secret_name}" ], createOrUpdateSecretForAuthenticatedUser: [ "PUT /user/codespaces/secrets/{secret_name}" ], createWithPrForAuthenticatedUser: [ "POST /repos/{owner}/{repo}/pulls/{pull_number}/codespaces" ], createWithRepoForAuthenticatedUser: [ "POST /repos/{owner}/{repo}/codespaces" ], deleteCodespacesBillingUsers: [ "DELETE /orgs/{org}/codespaces/billing/selected_users" ], deleteForAuthenticatedUser: ["DELETE /user/codespaces/{codespace_name}"], deleteFromOrganization: [ "DELETE /orgs/{org}/members/{username}/codespaces/{codespace_name}" ], deleteOrgSecret: ["DELETE /orgs/{org}/codespaces/secrets/{secret_name}"], deleteRepoSecret: [ "DELETE /repos/{owner}/{repo}/codespaces/secrets/{secret_name}" ], deleteSecretForAuthenticatedUser: [ "DELETE /user/codespaces/secrets/{secret_name}" ], exportForAuthenticatedUser: [ "POST /user/codespaces/{codespace_name}/exports" ], getCodespacesForUserInOrg: [ "GET /orgs/{org}/members/{username}/codespaces" ], getExportDetailsForAuthenticatedUser: [ "GET /user/codespaces/{codespace_name}/exports/{export_id}" ], getForAuthenticatedUser: ["GET /user/codespaces/{codespace_name}"], getOrgPublicKey: ["GET /orgs/{org}/codespaces/secrets/public-key"], getOrgSecret: ["GET /orgs/{org}/codespaces/secrets/{secret_name}"], getPublicKeyForAuthenticatedUser: [ "GET /user/codespaces/secrets/public-key" ], getRepoPublicKey: [ "GET /repos/{owner}/{repo}/codespaces/secrets/public-key" ], getRepoSecret: [ "GET /repos/{owner}/{repo}/codespaces/secrets/{secret_name}" ], getSecretForAuthenticatedUser: [ "GET /user/codespaces/secrets/{secret_name}" ], listDevcontainersInRepositoryForAuthenticatedUser: [ "GET /repos/{owner}/{repo}/codespaces/devcontainers" ], listForAuthenticatedUser: ["GET /user/codespaces"], listInOrganization: [ "GET /orgs/{org}/codespaces", {}, { renamedParameters: { org_id: "org" } } ], listInRepositoryForAuthenticatedUser: [ "GET /repos/{owner}/{repo}/codespaces" ], listOrgSecrets: ["GET /orgs/{org}/codespaces/secrets"], listRepoSecrets: ["GET /repos/{owner}/{repo}/codespaces/secrets"], listRepositoriesForSecretForAuthenticatedUser: [ "GET /user/codespaces/secrets/{secret_name}/repositories" ], listSecretsForAuthenticatedUser: ["GET /user/codespaces/secrets"], listSelectedReposForOrgSecret: [ "GET /orgs/{org}/codespaces/secrets/{secret_name}/repositories" ], preFlightWithRepoForAuthenticatedUser: [ "GET /repos/{owner}/{repo}/codespaces/new" ], publishForAuthenticatedUser: [ "POST /user/codespaces/{codespace_name}/publish" ], removeRepositoryForSecretForAuthenticatedUser: [ "DELETE /user/codespaces/secrets/{secret_name}/repositories/{repository_id}" ], removeSelectedRepoFromOrgSecret: [ "DELETE /orgs/{org}/codespaces/secrets/{secret_name}/repositories/{repository_id}" ], repoMachinesForAuthenticatedUser: [ "GET /repos/{owner}/{repo}/codespaces/machines" ], setCodespacesBilling: ["PUT /orgs/{org}/codespaces/billing"], setCodespacesBillingUsers: [ "POST /orgs/{org}/codespaces/billing/selected_users" ], setRepositoriesForSecretForAuthenticatedUser: [ "PUT /user/codespaces/secrets/{secret_name}/repositories" ], setSelectedReposForOrgSecret: [ "PUT /orgs/{org}/codespaces/secrets/{secret_name}/repositories" ], startForAuthenticatedUser: ["POST /user/codespaces/{codespace_name}/start"], stopForAuthenticatedUser: ["POST /user/codespaces/{codespace_name}/stop"], stopInOrganization: [ "POST /orgs/{org}/members/{username}/codespaces/{codespace_name}/stop" ], updateForAuthenticatedUser: ["PATCH /user/codespaces/{codespace_name}"] }, dependabot: { addSelectedRepoToOrgSecret: [ "PUT /orgs/{org}/dependabot/secrets/{secret_name}/repositories/{repository_id}" ], createOrUpdateOrgSecret: [ "PUT /orgs/{org}/dependabot/secrets/{secret_name}" ], createOrUpdateRepoSecret: [ "PUT /repos/{owner}/{repo}/dependabot/secrets/{secret_name}" ], deleteOrgSecret: ["DELETE /orgs/{org}/dependabot/secrets/{secret_name}"], deleteRepoSecret: [ "DELETE /repos/{owner}/{repo}/dependabot/secrets/{secret_name}" ], getAlert: ["GET /repos/{owner}/{repo}/dependabot/alerts/{alert_number}"], getOrgPublicKey: ["GET /orgs/{org}/dependabot/secrets/public-key"], getOrgSecret: ["GET /orgs/{org}/dependabot/secrets/{secret_name}"], getRepoPublicKey: [ "GET /repos/{owner}/{repo}/dependabot/secrets/public-key" ], getRepoSecret: [ "GET /repos/{owner}/{repo}/dependabot/secrets/{secret_name}" ], listAlertsForEnterprise: [ "GET /enterprises/{enterprise}/dependabot/alerts" ], listAlertsForOrg: ["GET /orgs/{org}/dependabot/alerts"], listAlertsForRepo: ["GET /repos/{owner}/{repo}/dependabot/alerts"], listOrgSecrets: ["GET /orgs/{org}/dependabot/secrets"], listRepoSecrets: ["GET /repos/{owner}/{repo}/dependabot/secrets"], listSelectedReposForOrgSecret: [ "GET /orgs/{org}/dependabot/secrets/{secret_name}/repositories" ], removeSelectedRepoFromOrgSecret: [ "DELETE /orgs/{org}/dependabot/secrets/{secret_name}/repositories/{repository_id}" ], setSelectedReposForOrgSecret: [ "PUT /orgs/{org}/dependabot/secrets/{secret_name}/repositories" ], updateAlert: [ "PATCH /repos/{owner}/{repo}/dependabot/alerts/{alert_number}" ] }, dependencyGraph: { createRepositorySnapshot: [ "POST /repos/{owner}/{repo}/dependency-graph/snapshots" ], diffRange: [ "GET /repos/{owner}/{repo}/dependency-graph/compare/{basehead}" ], exportSbom: ["GET /repos/{owner}/{repo}/dependency-graph/sbom"] }, emojis: { get: ["GET /emojis"] }, gists: { checkIsStarred: ["GET /gists/{gist_id}/star"], create: ["POST /gists"], createComment: ["POST /gists/{gist_id}/comments"], delete: ["DELETE /gists/{gist_id}"], deleteComment: ["DELETE /gists/{gist_id}/comments/{comment_id}"], fork: ["POST /gists/{gist_id}/forks"], get: ["GET /gists/{gist_id}"], getComment: ["GET /gists/{gist_id}/comments/{comment_id}"], getRevision: ["GET /gists/{gist_id}/{sha}"], list: ["GET /gists"], listComments: ["GET /gists/{gist_id}/comments"], listCommits: ["GET /gists/{gist_id}/commits"], listForUser: ["GET /users/{username}/gists"], listForks: ["GET /gists/{gist_id}/forks"], listPublic: ["GET /gists/public"], listStarred: ["GET /gists/starred"], star: ["PUT /gists/{gist_id}/star"], unstar: ["DELETE /gists/{gist_id}/star"], update: ["PATCH /gists/{gist_id}"], updateComment: ["PATCH /gists/{gist_id}/comments/{comment_id}"] }, git: { createBlob: ["POST /repos/{owner}/{repo}/git/blobs"], createCommit: ["POST /repos/{owner}/{repo}/git/commits"], createRef: ["POST /repos/{owner}/{repo}/git/refs"], createTag: ["POST /repos/{owner}/{repo}/git/tags"], createTree: ["POST /repos/{owner}/{repo}/git/trees"], deleteRef: ["DELETE /repos/{owner}/{repo}/git/refs/{ref}"], getBlob: ["GET /repos/{owner}/{repo}/git/blobs/{file_sha}"], getCommit: ["GET /repos/{owner}/{repo}/git/commits/{commit_sha}"], getRef: ["GET /repos/{owner}/{repo}/git/ref/{ref}"], getTag: ["GET /repos/{owner}/{repo}/git/tags/{tag_sha}"], getTree: ["GET /repos/{owner}/{repo}/git/trees/{tree_sha}"], listMatchingRefs: ["GET /repos/{owner}/{repo}/git/matching-refs/{ref}"], updateRef: ["PATCH /repos/{owner}/{repo}/git/refs/{ref}"] }, gitignore: { getAllTemplates: ["GET /gitignore/templates"], getTemplate: ["GET /gitignore/templates/{name}"] }, interactions: { getRestrictionsForAuthenticatedUser: ["GET /user/interaction-limits"], getRestrictionsForOrg: ["GET /orgs/{org}/interaction-limits"], getRestrictionsForRepo: ["GET /repos/{owner}/{repo}/interaction-limits"], getRestrictionsForYourPublicRepos: [ "GET /user/interaction-limits", {}, { renamed: ["interactions", "getRestrictionsForAuthenticatedUser"] } ], removeRestrictionsForAuthenticatedUser: ["DELETE /user/interaction-limits"], removeRestrictionsForOrg: ["DELETE /orgs/{org}/interaction-limits"], removeRestrictionsForRepo: [ "DELETE /repos/{owner}/{repo}/interaction-limits" ], removeRestrictionsForYourPublicRepos: [ "DELETE /user/interaction-limits", {}, { renamed: ["interactions", "removeRestrictionsForAuthenticatedUser"] } ], setRestrictionsForAuthenticatedUser: ["PUT /user/interaction-limits"], setRestrictionsForOrg: ["PUT /orgs/{org}/interaction-limits"], setRestrictionsForRepo: ["PUT /repos/{owner}/{repo}/interaction-limits"], setRestrictionsForYourPublicRepos: [ "PUT /user/interaction-limits", {}, { renamed: ["interactions", "setRestrictionsForAuthenticatedUser"] } ] }, issues: { addAssignees: [ "POST /repos/{owner}/{repo}/issues/{issue_number}/assignees" ], addLabels: ["POST /repos/{owner}/{repo}/issues/{issue_number}/labels"], checkUserCanBeAssigned: ["GET /repos/{owner}/{repo}/assignees/{assignee}"], checkUserCanBeAssignedToIssue: [ "GET /repos/{owner}/{repo}/issues/{issue_number}/assignees/{assignee}" ], create: ["POST /repos/{owner}/{repo}/issues"], createComment: [ "POST /repos/{owner}/{repo}/issues/{issue_number}/comments" ], createLabel: ["POST /repos/{owner}/{repo}/labels"], createMilestone: ["POST /repos/{owner}/{repo}/milestones"], deleteComment: [ "DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}" ], deleteLabel: ["DELETE /repos/{owner}/{repo}/labels/{name}"], deleteMilestone: [ "DELETE /repos/{owner}/{repo}/milestones/{milestone_number}" ], get: ["GET /repos/{owner}/{repo}/issues/{issue_number}"], getComment: ["GET /repos/{owner}/{repo}/issues/comments/{comment_id}"], getEvent: ["GET /repos/{owner}/{repo}/issues/events/{event_id}"], getLabel: ["GET /repos/{owner}/{repo}/labels/{name}"], getMilestone: ["GET /repos/{owner}/{repo}/milestones/{milestone_number}"], list: ["GET /issues"], listAssignees: ["GET /repos/{owner}/{repo}/assignees"], listComments: ["GET /repos/{owner}/{repo}/issues/{issue_number}/comments"], listCommentsForRepo: ["GET /repos/{owner}/{repo}/issues/comments"], listEvents: ["GET /repos/{owner}/{repo}/issues/{issue_number}/events"], listEventsForRepo: ["GET /repos/{owner}/{repo}/issues/events"], listEventsForTimeline: [ "GET /repos/{owner}/{repo}/issues/{issue_number}/timeline" ], listForAuthenticatedUser: ["GET /user/issues"], listForOrg: ["GET /orgs/{org}/issues"], listForRepo: ["GET /repos/{owner}/{repo}/issues"], listLabelsForMilestone: [ "GET /repos/{owner}/{repo}/milestones/{milestone_number}/labels" ], listLabelsForRepo: ["GET /repos/{owner}/{repo}/labels"], listLabelsOnIssue: [ "GET /repos/{owner}/{repo}/issues/{issue_number}/labels" ], listMilestones: ["GET /repos/{owner}/{repo}/milestones"], lock: ["PUT /repos/{owner}/{repo}/issues/{issue_number}/lock"], removeAllLabels: [ "DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels" ], removeAssignees: [ "DELETE /repos/{owner}/{repo}/issues/{issue_number}/assignees" ], removeLabel: [ "DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels/{name}" ], setLabels: ["PUT /repos/{owner}/{repo}/issues/{issue_number}/labels"], unlock: ["DELETE /repos/{owner}/{repo}/issues/{issue_number}/lock"], update: ["PATCH /repos/{owner}/{repo}/issues/{issue_number}"], updateComment: ["PATCH /repos/{owner}/{repo}/issues/comments/{comment_id}"], updateLabel: ["PATCH /repos/{owner}/{repo}/labels/{name}"], updateMilestone: [ "PATCH /repos/{owner}/{repo}/milestones/{milestone_number}" ] }, licenses: { get: ["GET /licenses/{license}"], getAllCommonlyUsed: ["GET /licenses"], getForRepo: ["GET /repos/{owner}/{repo}/license"] }, markdown: { render: ["POST /markdown"], renderRaw: [ "POST /markdown/raw", { headers: { "content-type": "text/plain; charset=utf-8" } } ] }, meta: { get: ["GET /meta"], getAllVersions: ["GET /versions"], getOctocat: ["GET /octocat"], getZen: ["GET /zen"], root: ["GET /"] }, migrations: { cancelImport: ["DELETE /repos/{owner}/{repo}/import"], deleteArchiveForAuthenticatedUser: [ "DELETE /user/migrations/{migration_id}/archive" ], deleteArchiveForOrg: [ "DELETE /orgs/{org}/migrations/{migration_id}/archive" ], downloadArchiveForOrg: [ "GET /orgs/{org}/migrations/{migration_id}/archive" ], getArchiveForAuthenticatedUser: [ "GET /user/migrations/{migration_id}/archive" ], getCommitAuthors: ["GET /repos/{owner}/{repo}/import/authors"], getImportStatus: ["GET /repos/{owner}/{repo}/import"], getLargeFiles: ["GET /repos/{owner}/{repo}/import/large_files"], getStatusForAuthenticatedUser: ["GET /user/migrations/{migration_id}"], getStatusForOrg: ["GET /orgs/{org}/migrations/{migration_id}"], listForAuthenticatedUser: ["GET /user/migrations"], listForOrg: ["GET /orgs/{org}/migrations"], listReposForAuthenticatedUser: [ "GET /user/migrations/{migration_id}/repositories" ], listReposForOrg: ["GET /orgs/{org}/migrations/{migration_id}/repositories"], listReposForUser: [ "GET /user/migrations/{migration_id}/repositories", {}, { renamed: ["migrations", "listReposForAuthenticatedUser"] } ], mapCommitAuthor: ["PATCH /repos/{owner}/{repo}/import/authors/{author_id}"], setLfsPreference: ["PATCH /repos/{owner}/{repo}/import/lfs"], startForAuthenticatedUser: ["POST /user/migrations"], startForOrg: ["POST /orgs/{org}/migrations"], startImport: ["PUT /repos/{owner}/{repo}/import"], unlockRepoForAuthenticatedUser: [ "DELETE /user/migrations/{migration_id}/repos/{repo_name}/lock" ], unlockRepoForOrg: [ "DELETE /orgs/{org}/migrations/{migration_id}/repos/{repo_name}/lock" ], updateImport: ["PATCH /repos/{owner}/{repo}/import"] }, orgs: { addSecurityManagerTeam: [ "PUT /orgs/{org}/security-managers/teams/{team_slug}" ], blockUser: ["PUT /orgs/{org}/blocks/{username}"], cancelInvitation: ["DELETE /orgs/{org}/invitations/{invitation_id}"], checkBlockedUser: ["GET /orgs/{org}/blocks/{username}"], checkMembershipForUser: ["GET /orgs/{org}/members/{username}"], checkPublicMembershipForUser: ["GET /orgs/{org}/public_members/{username}"], convertMemberToOutsideCollaborator: [ "PUT /orgs/{org}/outside_collaborators/{username}" ], createInvitation: ["POST /orgs/{org}/invitations"], createWebhook: ["POST /orgs/{org}/hooks"], delete: ["DELETE /orgs/{org}"], deleteWebhook: ["DELETE /orgs/{org}/hooks/{hook_id}"], enableOrDisableSecurityProductOnAllOrgRepos: [ "POST /orgs/{org}/{security_product}/{enablement}" ], get: ["GET /orgs/{org}"], getMembershipForAuthenticatedUser: ["GET /user/memberships/orgs/{org}"], getMembershipForUser: ["GET /orgs/{org}/memberships/{username}"], getWebhook: ["GET /orgs/{org}/hooks/{hook_id}"], getWebhookConfigForOrg: ["GET /orgs/{org}/hooks/{hook_id}/config"], getWebhookDelivery: [ "GET /orgs/{org}/hooks/{hook_id}/deliveries/{delivery_id}" ], list: ["GET /organizations"], listAppInstallations: ["GET /orgs/{org}/installations"], listBlockedUsers: ["GET /orgs/{org}/blocks"], listFailedInvitations: ["GET /orgs/{org}/failed_invitations"], listForAuthenticatedUser: ["GET /user/orgs"], listForUser: ["GET /users/{username}/orgs"], listInvitationTeams: ["GET /orgs/{org}/invitations/{invitation_id}/teams"], listMembers: ["GET /orgs/{org}/members"], listMembershipsForAuthenticatedUser: ["GET /user/memberships/orgs"], listOutsideCollaborators: ["GET /orgs/{org}/outside_collaborators"], listPatGrantRepositories: [ "GET /organizations/{org}/personal-access-tokens/{pat_id}/repositories" ], listPatGrantRequestRepositories: [ "GET /organizations/{org}/personal-access-token-requests/{pat_request_id}/repositories" ], listPatGrantRequests: [ "GET /organizations/{org}/personal-access-token-requests" ], listPatGrants: ["GET /organizations/{org}/personal-access-tokens"], listPendingInvitations: ["GET /orgs/{org}/invitations"], listPublicMembers: ["GET /orgs/{org}/public_members"], listSecurityManagerTeams: ["GET /orgs/{org}/security-managers"], listWebhookDeliveries: ["GET /orgs/{org}/hooks/{hook_id}/deliveries"], listWebhooks: ["GET /orgs/{org}/hooks"], pingWebhook: ["POST /orgs/{org}/hooks/{hook_id}/pings"], redeliverWebhookDelivery: [ "POST /orgs/{org}/hooks/{hook_id}/deliveries/{delivery_id}/attempts" ], removeMember: ["DELETE /orgs/{org}/members/{username}"], removeMembershipForUser: ["DELETE /orgs/{org}/memberships/{username}"], removeOutsideCollaborator: [ "DELETE /orgs/{org}/outside_collaborators/{username}" ], removePublicMembershipForAuthenticatedUser: [ "DELETE /orgs/{org}/public_members/{username}" ], removeSecurityManagerTeam: [ "DELETE /orgs/{org}/security-managers/teams/{team_slug}" ], reviewPatGrantRequest: [ "POST /organizations/{org}/personal-access-token-requests/{pat_request_id}" ], reviewPatGrantRequestsInBulk: [ "POST /organizations/{org}/personal-access-token-requests" ], setMembershipForUser: ["PUT /orgs/{org}/memberships/{username}"], setPublicMembershipForAuthenticatedUser: [ "PUT /orgs/{org}/public_members/{username}" ], unblockUser: ["DELETE /orgs/{org}/blocks/{username}"], update: ["PATCH /orgs/{org}"], updateMembershipForAuthenticatedUser: [ "PATCH /user/memberships/orgs/{org}" ], updatePatAccess: [ "POST /organizations/{org}/personal-access-tokens/{pat_id}" ], updatePatAccesses: ["POST /organizations/{org}/personal-access-tokens"], updateWebhook: ["PATCH /orgs/{org}/hooks/{hook_id}"], updateWebhookConfigForOrg: ["PATCH /orgs/{org}/hooks/{hook_id}/config"] }, packages: { deletePackageForAuthenticatedUser: [ "DELETE /user/packages/{package_type}/{package_name}" ], deletePackageForOrg: [ "DELETE /orgs/{org}/packages/{package_type}/{package_name}" ], deletePackageForUser: [ "DELETE /users/{username}/packages/{package_type}/{package_name}" ], deletePackageVersionForAuthenticatedUser: [ "DELETE /user/packages/{package_type}/{package_name}/versions/{package_version_id}" ], deletePackageVersionForOrg: [ "DELETE /orgs/{org}/packages/{package_type}/{package_name}/versions/{package_version_id}" ], deletePackageVersionForUser: [ "DELETE /users/{username}/packages/{package_type}/{package_name}/versions/{package_version_id}" ], getAllPackageVersionsForAPackageOwnedByAnOrg: [ "GET /orgs/{org}/packages/{package_type}/{package_name}/versions", {}, { renamed: ["packages", "getAllPackageVersionsForPackageOwnedByOrg"] } ], getAllPackageVersionsForAPackageOwnedByTheAuthenticatedUser: [ "GET /user/packages/{package_type}/{package_name}/versions", {}, { renamed: [ "packages", "getAllPackageVersionsForPackageOwnedByAuthenticatedUser" ] } ], getAllPackageVersionsForPackageOwnedByAuthenticatedUser: [ "GET /user/packages/{package_type}/{package_name}/versions" ], getAllPackageVersionsForPackageOwnedByOrg: [ "GET /orgs/{org}/packages/{package_type}/{package_name}/versions" ], getAllPackageVersionsForPackageOwnedByUser: [ "GET /users/{username}/packages/{package_type}/{package_name}/versions" ], getPackageForAuthenticatedUser: [ "GET /user/packages/{package_type}/{package_name}" ], getPackageForOrganization: [ "GET /orgs/{org}/packages/{package_type}/{package_name}" ], getPackageForUser: [ "GET /users/{username}/packages/{package_type}/{package_name}" ], getPackageVersionForAuthenticatedUser: [ "GET /user/packages/{package_type}/{package_name}/versions/{package_version_id}" ], getPackageVersionForOrganization: [ "GET /orgs/{org}/packages/{package_type}/{package_name}/versions/{package_version_id}" ], getPackageVersionForUser: [ "GET /users/{username}/packages/{package_type}/{package_name}/versions/{package_version_id}" ], listDockerMigrationConflictingPackagesForAuthenticatedUser: [ "GET /user/docker/conflicts" ], listDockerMigrationConflictingPackagesForOrganization: [ "GET /orgs/{org}/docker/conflicts" ], listDockerMigrationConflictingPackagesForUser: [ "GET /users/{username}/docker/conflicts" ], listPackagesForAuthenticatedUser: ["GET /user/packages"], listPackagesForOrganization: ["GET /orgs/{org}/packages"], listPackagesForUser: ["GET /users/{username}/packages"], restorePackageForAuthenticatedUser: [ "POST /user/packages/{package_type}/{package_name}/restore{?token}" ], restorePackageForOrg: [ "POST /orgs/{org}/packages/{package_type}/{package_name}/restore{?token}" ], restorePackageForUser: [ "POST /users/{username}/packages/{package_type}/{package_name}/restore{?token}" ], restorePackageVersionForAuthenticatedUser: [ "POST /user/packages/{package_type}/{package_name}/versions/{package_version_id}/restore" ], restorePackageVersionForOrg: [ "POST /orgs/{org}/packages/{package_type}/{package_name}/versions/{package_version_id}/restore" ], restorePackageVersionForUser: [ "POST /users/{username}/packages/{package_type}/{package_name}/versions/{package_version_id}/restore" ] }, projects: { addCollaborator: ["PUT /projects/{project_id}/collaborators/{username}"], createCard: ["POST /projects/columns/{column_id}/cards"], createColumn: ["POST /projects/{project_id}/columns"], createForAuthenticatedUser: ["POST /user/projects"], createForOrg: ["POST /orgs/{org}/projects"], createForRepo: ["POST /repos/{owner}/{repo}/projects"], delete: ["DELETE /projects/{project_id}"], deleteCard: ["DELETE /projects/columns/cards/{card_id}"], deleteColumn: ["DELETE /projects/columns/{column_id}"], get: ["GET /projects/{project_id}"], getCard: ["GET /projects/columns/cards/{card_id}"], getColumn: ["GET /projects/columns/{column_id}"], getPermissionForUser: [ "GET /projects/{project_id}/collaborators/{username}/permission" ], listCards: ["GET /projects/columns/{column_id}/cards"], listCollaborators: ["GET /projects/{project_id}/collaborators"], listColumns: ["GET /projects/{project_id}/columns"], listForOrg: ["GET /orgs/{org}/projects"], listForRepo: ["GET /repos/{owner}/{repo}/projects"], listForUser: ["GET /users/{username}/projects"], moveCard: ["POST /projects/columns/cards/{card_id}/moves"], moveColumn: ["POST /projects/columns/{column_id}/moves"], removeCollaborator: [ "DELETE /projects/{project_id}/collaborators/{username}" ], update: ["PATCH /projects/{project_id}"], updateCard: ["PATCH /projects/columns/cards/{card_id}"], updateColumn: ["PATCH /projects/columns/{column_id}"] }, pulls: { checkIfMerged: ["GET /repos/{owner}/{repo}/pulls/{pull_number}/merge"], create: ["POST /repos/{owner}/{repo}/pulls"], createReplyForReviewComment: [ "POST /repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies" ], createReview: ["POST /repos/{owner}/{repo}/pulls/{pull_number}/reviews"], createReviewComment: [ "POST /repos/{owner}/{repo}/pulls/{pull_number}/comments" ], deletePendingReview: [ "DELETE /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}" ], deleteReviewComment: [ "DELETE /repos/{owner}/{repo}/pulls/comments/{comment_id}" ], dismissReview: [ "PUT /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/dismissals" ], get: ["GET /repos/{owner}/{repo}/pulls/{pull_number}"], getReview: [ "GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}" ], getReviewComment: ["GET /repos/{owner}/{repo}/pulls/comments/{comment_id}"], list: ["GET /repos/{owner}/{repo}/pulls"], listCommentsForReview: [ "GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/comments" ], listCommits: ["GET /repos/{owner}/{repo}/pulls/{pull_number}/commits"], listFiles: ["GET /repos/{owner}/{repo}/pulls/{pull_number}/files"], listRequestedReviewers: [ "GET /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers" ], listReviewComments: [ "GET /repos/{owner}/{repo}/pulls/{pull_number}/comments" ], listReviewCommentsForRepo: ["GET /repos/{owner}/{repo}/pulls/comments"], listReviews: ["GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews"], merge: ["PUT /repos/{owner}/{repo}/pulls/{pull_number}/merge"], removeRequestedReviewers: [ "DELETE /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers" ], requestReviewers: [ "POST /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers" ], submitReview: [ "POST /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}/events" ], update: ["PATCH /repos/{owner}/{repo}/pulls/{pull_number}"], updateBranch: [ "PUT /repos/{owner}/{repo}/pulls/{pull_number}/update-branch" ], updateReview: [ "PUT /repos/{owner}/{repo}/pulls/{pull_number}/reviews/{review_id}" ], updateReviewComment: [ "PATCH /repos/{owner}/{repo}/pulls/comments/{comment_id}" ] }, rateLimit: { get: ["GET /rate_limit"] }, reactions: { createForCommitComment: [ "POST /repos/{owner}/{repo}/comments/{comment_id}/reactions" ], createForIssue: [ "POST /repos/{owner}/{repo}/issues/{issue_number}/reactions" ], createForIssueComment: [ "POST /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions" ], createForPullRequestReviewComment: [ "POST /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions" ], createForRelease: [ "POST /repos/{owner}/{repo}/releases/{release_id}/reactions" ], createForTeamDiscussionCommentInOrg: [ "POST /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions" ], createForTeamDiscussionInOrg: [ "POST /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions" ], deleteForCommitComment: [ "DELETE /repos/{owner}/{repo}/comments/{comment_id}/reactions/{reaction_id}" ], deleteForIssue: [ "DELETE /repos/{owner}/{repo}/issues/{issue_number}/reactions/{reaction_id}" ], deleteForIssueComment: [ "DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions/{reaction_id}" ], deleteForPullRequestComment: [ "DELETE /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions/{reaction_id}" ], deleteForRelease: [ "DELETE /repos/{owner}/{repo}/releases/{release_id}/reactions/{reaction_id}" ], deleteForTeamDiscussion: [ "DELETE /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions/{reaction_id}" ], deleteForTeamDiscussionComment: [ "DELETE /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions/{reaction_id}" ], listForCommitComment: [ "GET /repos/{owner}/{repo}/comments/{comment_id}/reactions" ], listForIssue: ["GET /repos/{owner}/{repo}/issues/{issue_number}/reactions"], listForIssueComment: [ "GET /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions" ], listForPullRequestReviewComment: [ "GET /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions" ], listForRelease: [ "GET /repos/{owner}/{repo}/releases/{release_id}/reactions" ], listForTeamDiscussionCommentInOrg: [ "GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}/reactions" ], listForTeamDiscussionInOrg: [ "GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/reactions" ] }, repos: { acceptInvitation: [ "PATCH /user/repository_invitations/{invitation_id}", {}, { renamed: ["repos", "acceptInvitationForAuthenticatedUser"] } ], acceptInvitationForAuthenticatedUser: [ "PATCH /user/repository_invitations/{invitation_id}" ], addAppAccessRestrictions: [ "POST /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/apps", {}, { mapToData: "apps" } ], addCollaborator: ["PUT /repos/{owner}/{repo}/collaborators/{username}"], addStatusCheckContexts: [ "POST /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts", {}, { mapToData: "contexts" } ], addTeamAccessRestrictions: [ "POST /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams", {}, { mapToData: "teams" } ], addUserAccessRestrictions: [ "POST /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/users", {}, { mapToData: "users" } ], checkCollaborator: ["GET /repos/{owner}/{repo}/collaborators/{username}"], checkVulnerabilityAlerts: [ "GET /repos/{owner}/{repo}/vulnerability-alerts" ], codeownersErrors: ["GET /repos/{owner}/{repo}/codeowners/errors"], compareCommits: ["GET /repos/{owner}/{repo}/compare/{base}...{head}"], compareCommitsWithBasehead: [ "GET /repos/{owner}/{repo}/compare/{basehead}" ], createAutolink: ["POST /repos/{owner}/{repo}/autolinks"], createCommitComment: [ "POST /repos/{owner}/{repo}/commits/{commit_sha}/comments" ], createCommitSignatureProtection: [ "POST /repos/{owner}/{repo}/branches/{branch}/protection/required_signatures" ], createCommitStatus: ["POST /repos/{owner}/{repo}/statuses/{sha}"], createDeployKey: ["POST /repos/{owner}/{repo}/keys"], createDeployment: ["POST /repos/{owner}/{repo}/deployments"], createDeploymentBranchPolicy: [ "POST /repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies" ], createDeploymentProtectionRule: [ "POST /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules" ], createDeploymentStatus: [ "POST /repos/{owner}/{repo}/deployments/{deployment_id}/statuses" ], createDispatchEvent: ["POST /repos/{owner}/{repo}/dispatches"], createForAuthenticatedUser: ["POST /user/repos"], createFork: ["POST /repos/{owner}/{repo}/forks"], createInOrg: ["POST /orgs/{org}/repos"], createOrUpdateEnvironment: [ "PUT /repos/{owner}/{repo}/environments/{environment_name}" ], createOrUpdateFileContents: ["PUT /repos/{owner}/{repo}/contents/{path}"], createOrgRuleset: ["POST /orgs/{org}/rulesets"], createPagesDeployment: ["POST /repos/{owner}/{repo}/pages/deployment"], createPagesSite: ["POST /repos/{owner}/{repo}/pages"], createRelease: ["POST /repos/{owner}/{repo}/releases"], createRepoRuleset: ["POST /repos/{owner}/{repo}/rulesets"], createTagProtection: ["POST /repos/{owner}/{repo}/tags/protection"], createUsingTemplate: [ "POST /repos/{template_owner}/{template_repo}/generate" ], createWebhook: ["POST /repos/{owner}/{repo}/hooks"], declineInvitation: [ "DELETE /user/repository_invitations/{invitation_id}", {}, { renamed: ["repos", "declineInvitationForAuthenticatedUser"] } ], declineInvitationForAuthenticatedUser: [ "DELETE /user/repository_invitations/{invitation_id}" ], delete: ["DELETE /repos/{owner}/{repo}"], deleteAccessRestrictions: [ "DELETE /repos/{owner}/{repo}/branches/{branch}/protection/restrictions" ], deleteAdminBranchProtection: [ "DELETE /repos/{owner}/{repo}/branches/{branch}/protection/enforce_admins" ], deleteAnEnvironment: [ "DELETE /repos/{owner}/{repo}/environments/{environment_name}" ], deleteAutolink: ["DELETE /repos/{owner}/{repo}/autolinks/{autolink_id}"], deleteBranchProtection: [ "DELETE /repos/{owner}/{repo}/branches/{branch}/protection" ], deleteCommitComment: ["DELETE /repos/{owner}/{repo}/comments/{comment_id}"], deleteCommitSignatureProtection: [ "DELETE /repos/{owner}/{repo}/branches/{branch}/protection/required_signatures" ], deleteDeployKey: ["DELETE /repos/{owner}/{repo}/keys/{key_id}"], deleteDeployment: [ "DELETE /repos/{owner}/{repo}/deployments/{deployment_id}" ], deleteDeploymentBranchPolicy: [ "DELETE /repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies/{branch_policy_id}" ], deleteFile: ["DELETE /repos/{owner}/{repo}/contents/{path}"], deleteInvitation: [ "DELETE /repos/{owner}/{repo}/invitations/{invitation_id}" ], deleteOrgRuleset: ["DELETE /orgs/{org}/rulesets/{ruleset_id}"], deletePagesSite: ["DELETE /repos/{owner}/{repo}/pages"], deletePullRequestReviewProtection: [ "DELETE /repos/{owner}/{repo}/branches/{branch}/protection/required_pull_request_reviews" ], deleteRelease: ["DELETE /repos/{owner}/{repo}/releases/{release_id}"], deleteReleaseAsset: [ "DELETE /repos/{owner}/{repo}/releases/assets/{asset_id}" ], deleteRepoRuleset: ["DELETE /repos/{owner}/{repo}/rulesets/{ruleset_id}"], deleteTagProtection: [ "DELETE /repos/{owner}/{repo}/tags/protection/{tag_protection_id}" ], deleteWebhook: ["DELETE /repos/{owner}/{repo}/hooks/{hook_id}"], disableAutomatedSecurityFixes: [ "DELETE /repos/{owner}/{repo}/automated-security-fixes" ], disableDeploymentProtectionRule: [ "DELETE /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules/{protection_rule_id}" ], disableLfsForRepo: ["DELETE /repos/{owner}/{repo}/lfs"], disableVulnerabilityAlerts: [ "DELETE /repos/{owner}/{repo}/vulnerability-alerts" ], downloadArchive: [ "GET /repos/{owner}/{repo}/zipball/{ref}", {}, { renamed: ["repos", "downloadZipballArchive"] } ], downloadTarballArchive: ["GET /repos/{owner}/{repo}/tarball/{ref}"], downloadZipballArchive: ["GET /repos/{owner}/{repo}/zipball/{ref}"], enableAutomatedSecurityFixes: [ "PUT /repos/{owner}/{repo}/automated-security-fixes" ], enableLfsForRepo: ["PUT /repos/{owner}/{repo}/lfs"], enableVulnerabilityAlerts: [ "PUT /repos/{owner}/{repo}/vulnerability-alerts" ], generateReleaseNotes: [ "POST /repos/{owner}/{repo}/releases/generate-notes" ], get: ["GET /repos/{owner}/{repo}"], getAccessRestrictions: [ "GET /repos/{owner}/{repo}/branches/{branch}/protection/restrictions" ], getAdminBranchProtection: [ "GET /repos/{owner}/{repo}/branches/{branch}/protection/enforce_admins" ], getAllDeploymentProtectionRules: [ "GET /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules" ], getAllEnvironments: ["GET /repos/{owner}/{repo}/environments"], getAllStatusCheckContexts: [ "GET /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts" ], getAllTopics: ["GET /repos/{owner}/{repo}/topics"], getAppsWithAccessToProtectedBranch: [ "GET /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/apps" ], getAutolink: ["GET /repos/{owner}/{repo}/autolinks/{autolink_id}"], getBranch: ["GET /repos/{owner}/{repo}/branches/{branch}"], getBranchProtection: [ "GET /repos/{owner}/{repo}/branches/{branch}/protection" ], getBranchRules: ["GET /repos/{owner}/{repo}/rules/branches/{branch}"], getClones: ["GET /repos/{owner}/{repo}/traffic/clones"], getCodeFrequencyStats: ["GET /repos/{owner}/{repo}/stats/code_frequency"], getCollaboratorPermissionLevel: [ "GET /repos/{owner}/{repo}/collaborators/{username}/permission" ], getCombinedStatusForRef: ["GET /repos/{owner}/{repo}/commits/{ref}/status"], getCommit: ["GET /repos/{owner}/{repo}/commits/{ref}"], getCommitActivityStats: ["GET /repos/{owner}/{repo}/stats/commit_activity"], getCommitComment: ["GET /repos/{owner}/{repo}/comments/{comment_id}"], getCommitSignatureProtection: [ "GET /repos/{owner}/{repo}/branches/{branch}/protection/required_signatures" ], getCommunityProfileMetrics: ["GET /repos/{owner}/{repo}/community/profile"], getContent: ["GET /repos/{owner}/{repo}/contents/{path}"], getContributorsStats: ["GET /repos/{owner}/{repo}/stats/contributors"], getCustomDeploymentProtectionRule: [ "GET /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules/{protection_rule_id}" ], getDeployKey: ["GET /repos/{owner}/{repo}/keys/{key_id}"], getDeployment: ["GET /repos/{owner}/{repo}/deployments/{deployment_id}"], getDeploymentBranchPolicy: [ "GET /repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies/{branch_policy_id}" ], getDeploymentStatus: [ "GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses/{status_id}" ], getEnvironment: [ "GET /repos/{owner}/{repo}/environments/{environment_name}" ], getLatestPagesBuild: ["GET /repos/{owner}/{repo}/pages/builds/latest"], getLatestRelease: ["GET /repos/{owner}/{repo}/releases/latest"], getOrgRuleset: ["GET /orgs/{org}/rulesets/{ruleset_id}"], getOrgRulesets: ["GET /orgs/{org}/rulesets"], getPages: ["GET /repos/{owner}/{repo}/pages"], getPagesBuild: ["GET /repos/{owner}/{repo}/pages/builds/{build_id}"], getPagesHealthCheck: ["GET /repos/{owner}/{repo}/pages/health"], getParticipationStats: ["GET /repos/{owner}/{repo}/stats/participation"], getPullRequestReviewProtection: [ "GET /repos/{owner}/{repo}/branches/{branch}/protection/required_pull_request_reviews" ], getPunchCardStats: ["GET /repos/{owner}/{repo}/stats/punch_card"], getReadme: ["GET /repos/{owner}/{repo}/readme"], getReadmeInDirectory: ["GET /repos/{owner}/{repo}/readme/{dir}"], getRelease: ["GET /repos/{owner}/{repo}/releases/{release_id}"], getReleaseAsset: ["GET /repos/{owner}/{repo}/releases/assets/{asset_id}"], getReleaseByTag: ["GET /repos/{owner}/{repo}/releases/tags/{tag}"], getRepoRuleset: ["GET /repos/{owner}/{repo}/rulesets/{ruleset_id}"], getRepoRulesets: ["GET /repos/{owner}/{repo}/rulesets"], getStatusChecksProtection: [ "GET /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks" ], getTeamsWithAccessToProtectedBranch: [ "GET /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams" ], getTopPaths: ["GET /repos/{owner}/{repo}/traffic/popular/paths"], getTopReferrers: ["GET /repos/{owner}/{repo}/traffic/popular/referrers"], getUsersWithAccessToProtectedBranch: [ "GET /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/users" ], getViews: ["GET /repos/{owner}/{repo}/traffic/views"], getWebhook: ["GET /repos/{owner}/{repo}/hooks/{hook_id}"], getWebhookConfigForRepo: [ "GET /repos/{owner}/{repo}/hooks/{hook_id}/config" ], getWebhookDelivery: [ "GET /repos/{owner}/{repo}/hooks/{hook_id}/deliveries/{delivery_id}" ], listAutolinks: ["GET /repos/{owner}/{repo}/autolinks"], listBranches: ["GET /repos/{owner}/{repo}/branches"], listBranchesForHeadCommit: [ "GET /repos/{owner}/{repo}/commits/{commit_sha}/branches-where-head" ], listCollaborators: ["GET /repos/{owner}/{repo}/collaborators"], listCommentsForCommit: [ "GET /repos/{owner}/{repo}/commits/{commit_sha}/comments" ], listCommitCommentsForRepo: ["GET /repos/{owner}/{repo}/comments"], listCommitStatusesForRef: [ "GET /repos/{owner}/{repo}/commits/{ref}/statuses" ], listCommits: ["GET /repos/{owner}/{repo}/commits"], listContributors: ["GET /repos/{owner}/{repo}/contributors"], listCustomDeploymentRuleIntegrations: [ "GET /repos/{owner}/{repo}/environments/{environment_name}/deployment_protection_rules/apps" ], listDeployKeys: ["GET /repos/{owner}/{repo}/keys"], listDeploymentBranchPolicies: [ "GET /repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies" ], listDeploymentStatuses: [ "GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses" ], listDeployments: ["GET /repos/{owner}/{repo}/deployments"], listForAuthenticatedUser: ["GET /user/repos"], listForOrg: ["GET /orgs/{org}/repos"], listForUser: ["GET /users/{username}/repos"], listForks: ["GET /repos/{owner}/{repo}/forks"], listInvitations: ["GET /repos/{owner}/{repo}/invitations"], listInvitationsForAuthenticatedUser: ["GET /user/repository_invitations"], listLanguages: ["GET /repos/{owner}/{repo}/languages"], listPagesBuilds: ["GET /repos/{owner}/{repo}/pages/builds"], listPublic: ["GET /repositories"], listPullRequestsAssociatedWithCommit: [ "GET /repos/{owner}/{repo}/commits/{commit_sha}/pulls" ], listReleaseAssets: [ "GET /repos/{owner}/{repo}/releases/{release_id}/assets" ], listReleases: ["GET /repos/{owner}/{repo}/releases"], listTagProtection: ["GET /repos/{owner}/{repo}/tags/protection"], listTags: ["GET /repos/{owner}/{repo}/tags"], listTeams: ["GET /repos/{owner}/{repo}/teams"], listWebhookDeliveries: [ "GET /repos/{owner}/{repo}/hooks/{hook_id}/deliveries" ], listWebhooks: ["GET /repos/{owner}/{repo}/hooks"], merge: ["POST /repos/{owner}/{repo}/merges"], mergeUpstream: ["POST /repos/{owner}/{repo}/merge-upstream"], pingWebhook: ["POST /repos/{owner}/{repo}/hooks/{hook_id}/pings"], redeliverWebhookDelivery: [ "POST /repos/{owner}/{repo}/hooks/{hook_id}/deliveries/{delivery_id}/attempts" ], removeAppAccessRestrictions: [ "DELETE /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/apps", {}, { mapToData: "apps" } ], removeCollaborator: [ "DELETE /repos/{owner}/{repo}/collaborators/{username}" ], removeStatusCheckContexts: [ "DELETE /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts", {}, { mapToData: "contexts" } ], removeStatusCheckProtection: [ "DELETE /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks" ], removeTeamAccessRestrictions: [ "DELETE /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams", {}, { mapToData: "teams" } ], removeUserAccessRestrictions: [ "DELETE /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/users", {}, { mapToData: "users" } ], renameBranch: ["POST /repos/{owner}/{repo}/branches/{branch}/rename"], replaceAllTopics: ["PUT /repos/{owner}/{repo}/topics"], requestPagesBuild: ["POST /repos/{owner}/{repo}/pages/builds"], setAdminBranchProtection: [ "POST /repos/{owner}/{repo}/branches/{branch}/protection/enforce_admins" ], setAppAccessRestrictions: [ "PUT /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/apps", {}, { mapToData: "apps" } ], setStatusCheckContexts: [ "PUT /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts", {}, { mapToData: "contexts" } ], setTeamAccessRestrictions: [ "PUT /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams", {}, { mapToData: "teams" } ], setUserAccessRestrictions: [ "PUT /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/users", {}, { mapToData: "users" } ], testPushWebhook: ["POST /repos/{owner}/{repo}/hooks/{hook_id}/tests"], transfer: ["POST /repos/{owner}/{repo}/transfer"], update: ["PATCH /repos/{owner}/{repo}"], updateBranchProtection: [ "PUT /repos/{owner}/{repo}/branches/{branch}/protection" ], updateCommitComment: ["PATCH /repos/{owner}/{repo}/comments/{comment_id}"], updateDeploymentBranchPolicy: [ "PUT /repos/{owner}/{repo}/environments/{environment_name}/deployment-branch-policies/{branch_policy_id}" ], updateInformationAboutPagesSite: ["PUT /repos/{owner}/{repo}/pages"], updateInvitation: [ "PATCH /repos/{owner}/{repo}/invitations/{invitation_id}" ], updateOrgRuleset: ["PUT /orgs/{org}/rulesets/{ruleset_id}"], updatePullRequestReviewProtection: [ "PATCH /repos/{owner}/{repo}/branches/{branch}/protection/required_pull_request_reviews" ], updateRelease: ["PATCH /repos/{owner}/{repo}/releases/{release_id}"], updateReleaseAsset: [ "PATCH /repos/{owner}/{repo}/releases/assets/{asset_id}" ], updateRepoRuleset: ["PUT /repos/{owner}/{repo}/rulesets/{ruleset_id}"], updateStatusCheckPotection: [ "PATCH /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks", {}, { renamed: ["repos", "updateStatusCheckProtection"] } ], updateStatusCheckProtection: [ "PATCH /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks" ], updateWebhook: ["PATCH /repos/{owner}/{repo}/hooks/{hook_id}"], updateWebhookConfigForRepo: [ "PATCH /repos/{owner}/{repo}/hooks/{hook_id}/config" ], uploadReleaseAsset: [ "POST /repos/{owner}/{repo}/releases/{release_id}/assets{?name,label}", { baseUrl: "https://uploads.github.com" } ] }, search: { code: ["GET /search/code"], commits: ["GET /search/commits"], issuesAndPullRequests: ["GET /search/issues"], labels: ["GET /search/labels"], repos: ["GET /search/repositories"], topics: ["GET /search/topics"], users: ["GET /search/users"] }, secretScanning: { getAlert: [ "GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}" ], listAlertsForEnterprise: [ "GET /enterprises/{enterprise}/secret-scanning/alerts" ], listAlertsForOrg: ["GET /orgs/{org}/secret-scanning/alerts"], listAlertsForRepo: ["GET /repos/{owner}/{repo}/secret-scanning/alerts"], listLocationsForAlert: [ "GET /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}/locations" ], updateAlert: [ "PATCH /repos/{owner}/{repo}/secret-scanning/alerts/{alert_number}" ] }, securityAdvisories: { createPrivateVulnerabilityReport: [ "POST /repos/{owner}/{repo}/security-advisories/reports" ], createRepositoryAdvisory: [ "POST /repos/{owner}/{repo}/security-advisories" ], getRepositoryAdvisory: [ "GET /repos/{owner}/{repo}/security-advisories/{ghsa_id}" ], listRepositoryAdvisories: ["GET /repos/{owner}/{repo}/security-advisories"], updateRepositoryAdvisory: [ "PATCH /repos/{owner}/{repo}/security-advisories/{ghsa_id}" ] }, teams: { addOrUpdateMembershipForUserInOrg: [ "PUT /orgs/{org}/teams/{team_slug}/memberships/{username}" ], addOrUpdateProjectPermissionsInOrg: [ "PUT /orgs/{org}/teams/{team_slug}/projects/{project_id}" ], addOrUpdateRepoPermissionsInOrg: [ "PUT /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}" ], checkPermissionsForProjectInOrg: [ "GET /orgs/{org}/teams/{team_slug}/projects/{project_id}" ], checkPermissionsForRepoInOrg: [ "GET /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}" ], create: ["POST /orgs/{org}/teams"], createDiscussionCommentInOrg: [ "POST /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments" ], createDiscussionInOrg: ["POST /orgs/{org}/teams/{team_slug}/discussions"], deleteDiscussionCommentInOrg: [ "DELETE /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}" ], deleteDiscussionInOrg: [ "DELETE /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}" ], deleteInOrg: ["DELETE /orgs/{org}/teams/{team_slug}"], getByName: ["GET /orgs/{org}/teams/{team_slug}"], getDiscussionCommentInOrg: [ "GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}" ], getDiscussionInOrg: [ "GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}" ], getMembershipForUserInOrg: [ "GET /orgs/{org}/teams/{team_slug}/memberships/{username}" ], list: ["GET /orgs/{org}/teams"], listChildInOrg: ["GET /orgs/{org}/teams/{team_slug}/teams"], listDiscussionCommentsInOrg: [ "GET /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments" ], listDiscussionsInOrg: ["GET /orgs/{org}/teams/{team_slug}/discussions"], listForAuthenticatedUser: ["GET /user/teams"], listMembersInOrg: ["GET /orgs/{org}/teams/{team_slug}/members"], listPendingInvitationsInOrg: [ "GET /orgs/{org}/teams/{team_slug}/invitations" ], listProjectsInOrg: ["GET /orgs/{org}/teams/{team_slug}/projects"], listReposInOrg: ["GET /orgs/{org}/teams/{team_slug}/repos"], removeMembershipForUserInOrg: [ "DELETE /orgs/{org}/teams/{team_slug}/memberships/{username}" ], removeProjectInOrg: [ "DELETE /orgs/{org}/teams/{team_slug}/projects/{project_id}" ], removeRepoInOrg: [ "DELETE /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo}" ], updateDiscussionCommentInOrg: [ "PATCH /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments/{comment_number}" ], updateDiscussionInOrg: [ "PATCH /orgs/{org}/teams/{team_slug}/discussions/{discussion_number}" ], updateInOrg: ["PATCH /orgs/{org}/teams/{team_slug}"] }, users: { addEmailForAuthenticated: [ "POST /user/emails", {}, { renamed: ["users", "addEmailForAuthenticatedUser"] } ], addEmailForAuthenticatedUser: ["POST /user/emails"], addSocialAccountForAuthenticatedUser: ["POST /user/social_accounts"], block: ["PUT /user/blocks/{username}"], checkBlocked: ["GET /user/blocks/{username}"], checkFollowingForUser: ["GET /users/{username}/following/{target_user}"], checkPersonIsFollowedByAuthenticated: ["GET /user/following/{username}"], createGpgKeyForAuthenticated: [ "POST /user/gpg_keys", {}, { renamed: ["users", "createGpgKeyForAuthenticatedUser"] } ], createGpgKeyForAuthenticatedUser: ["POST /user/gpg_keys"], createPublicSshKeyForAuthenticated: [ "POST /user/keys", {}, { renamed: ["users", "createPublicSshKeyForAuthenticatedUser"] } ], createPublicSshKeyForAuthenticatedUser: ["POST /user/keys"], createSshSigningKeyForAuthenticatedUser: ["POST /user/ssh_signing_keys"], deleteEmailForAuthenticated: [ "DELETE /user/emails", {}, { renamed: ["users", "deleteEmailForAuthenticatedUser"] } ], deleteEmailForAuthenticatedUser: ["DELETE /user/emails"], deleteGpgKeyForAuthenticated: [ "DELETE /user/gpg_keys/{gpg_key_id}", {}, { renamed: ["users", "deleteGpgKeyForAuthenticatedUser"] } ], deleteGpgKeyForAuthenticatedUser: ["DELETE /user/gpg_keys/{gpg_key_id}"], deletePublicSshKeyForAuthenticated: [ "DELETE /user/keys/{key_id}", {}, { renamed: ["users", "deletePublicSshKeyForAuthenticatedUser"] } ], deletePublicSshKeyForAuthenticatedUser: ["DELETE /user/keys/{key_id}"], deleteSocialAccountForAuthenticatedUser: ["DELETE /user/social_accounts"], deleteSshSigningKeyForAuthenticatedUser: [ "DELETE /user/ssh_signing_keys/{ssh_signing_key_id}" ], follow: ["PUT /user/following/{username}"], getAuthenticated: ["GET /user"], getByUsername: ["GET /users/{username}"], getContextForUser: ["GET /users/{username}/hovercard"], getGpgKeyForAuthenticated: [ "GET /user/gpg_keys/{gpg_key_id}", {}, { renamed: ["users", "getGpgKeyForAuthenticatedUser"] } ], getGpgKeyForAuthenticatedUser: ["GET /user/gpg_keys/{gpg_key_id}"], getPublicSshKeyForAuthenticated: [ "GET /user/keys/{key_id}", {}, { renamed: ["users", "getPublicSshKeyForAuthenticatedUser"] } ], getPublicSshKeyForAuthenticatedUser: ["GET /user/keys/{key_id}"], getSshSigningKeyForAuthenticatedUser: [ "GET /user/ssh_signing_keys/{ssh_signing_key_id}" ], list: ["GET /users"], listBlockedByAuthenticated: [ "GET /user/blocks", {}, { renamed: ["users", "listBlockedByAuthenticatedUser"] } ], listBlockedByAuthenticatedUser: ["GET /user/blocks"], listEmailsForAuthenticated: [ "GET /user/emails", {}, { renamed: ["users", "listEmailsForAuthenticatedUser"] } ], listEmailsForAuthenticatedUser: ["GET /user/emails"], listFollowedByAuthenticated: [ "GET /user/following", {}, { renamed: ["users", "listFollowedByAuthenticatedUser"] } ], listFollowedByAuthenticatedUser: ["GET /user/following"], listFollowersForAuthenticatedUser: ["GET /user/followers"], listFollowersForUser: ["GET /users/{username}/followers"], listFollowingForUser: ["GET /users/{username}/following"], listGpgKeysForAuthenticated: [ "GET /user/gpg_keys", {}, { renamed: ["users", "listGpgKeysForAuthenticatedUser"] } ], listGpgKeysForAuthenticatedUser: ["GET /user/gpg_keys"], listGpgKeysForUser: ["GET /users/{username}/gpg_keys"], listPublicEmailsForAuthenticated: [ "GET /user/public_emails", {}, { renamed: ["users", "listPublicEmailsForAuthenticatedUser"] } ], listPublicEmailsForAuthenticatedUser: ["GET /user/public_emails"], listPublicKeysForUser: ["GET /users/{username}/keys"], listPublicSshKeysForAuthenticated: [ "GET /user/keys", {}, { renamed: ["users", "listPublicSshKeysForAuthenticatedUser"] } ], listPublicSshKeysForAuthenticatedUser: ["GET /user/keys"], listSocialAccountsForAuthenticatedUser: ["GET /user/social_accounts"], listSocialAccountsForUser: ["GET /users/{username}/social_accounts"], listSshSigningKeysForAuthenticatedUser: ["GET /user/ssh_signing_keys"], listSshSigningKeysForUser: ["GET /users/{username}/ssh_signing_keys"], setPrimaryEmailVisibilityForAuthenticated: [ "PATCH /user/email/visibility", {}, { renamed: ["users", "setPrimaryEmailVisibilityForAuthenticatedUser"] } ], setPrimaryEmailVisibilityForAuthenticatedUser: [ "PATCH /user/email/visibility" ], unblock: ["DELETE /user/blocks/{username}"], unfollow: ["DELETE /user/following/{username}"], updateAuthenticated: ["PATCH /user"] } }; var endpoints_default = Endpoints; var endpointMethodsMap = /* @__PURE__ */ new Map(); for (const [scope, endpoints] of Object.entries(endpoints_default)) { for (const [methodName, endpoint2] of Object.entries(endpoints)) { const [route, defaults, decorations] = endpoint2; const [method, url] = route.split(/ /); const endpointDefaults = Object.assign( { method, url }, defaults ); if (!endpointMethodsMap.has(scope)) { endpointMethodsMap.set(scope, /* @__PURE__ */ new Map()); } endpointMethodsMap.get(scope).set(methodName, { scope, methodName, endpointDefaults, decorations }); } } var handler = { get({ octokit, scope, cache }, methodName) { if (cache[methodName]) { return cache[methodName]; } const { decorations, endpointDefaults } = endpointMethodsMap.get(scope).get(methodName); if (decorations) { cache[methodName] = decorate( octokit, scope, methodName, endpointDefaults, decorations ); } else { cache[methodName] = octokit.request.defaults(endpointDefaults); } return cache[methodName]; } }; function endpointsToMethods(octokit) { const newMethods = {}; for (const scope of endpointMethodsMap.keys()) { newMethods[scope] = new Proxy({ octokit, scope, cache: {} }, handler); } return newMethods; } function decorate(octokit, scope, methodName, defaults, decorations) { const requestWithDefaults = octokit.request.defaults(defaults); function withDecorations(...args) { let options = requestWithDefaults.endpoint.merge(...args); if (decorations.mapToData) { options = Object.assign({}, options, { data: options[decorations.mapToData], [decorations.mapToData]: void 0 }); return requestWithDefaults(options); } if (decorations.renamed) { const [newScope, newMethodName] = decorations.renamed; octokit.log.warn( `octokit.${scope}.${methodName}() has been renamed to octokit.${newScope}.${newMethodName}()` ); } if (decorations.deprecated) { octokit.log.warn(decorations.deprecated); } if (decorations.renamedParameters) { const options2 = requestWithDefaults.endpoint.merge(...args); for (const [name, alias] of Object.entries( decorations.renamedParameters )) { if (name in options2) { octokit.log.warn( `"${name}" parameter is deprecated for "octokit.${scope}.${methodName}()". Use "${alias}" instead` ); if (!(alias in options2)) { options2[alias] = options2[name]; } delete options2[name]; } } return requestWithDefaults(options2); } return requestWithDefaults(...args); } return Object.assign(withDecorations, requestWithDefaults); } function restEndpointMethods(octokit) { const api = endpointsToMethods(octokit); return { rest: api }; } restEndpointMethods.VERSION = VERSION7; function legacyRestEndpointMethods(octokit) { const api = endpointsToMethods(octokit); return { ...api, rest: api }; } legacyRestEndpointMethods.VERSION = VERSION7; // node_modules/@octokit/rest/dist-web/index.js var VERSION8 = "19.0.13"; var Octokit2 = Octokit.plugin( requestLog, legacyRestEndpointMethods, paginateRest ).defaults({ userAgent: `octokit-rest.js/${VERSION8}` }); // github-service.ts var import_obsidian = require("obsidian"); init_i18n_simple(); var GitHubService = class { constructor(token) { this.rateLimitInfo = null; this.octokit = new Octokit2({ auth: token }); } updateToken(token) { this.octokit = new Octokit2({ auth: token }); this.rateLimitInfo = null; } // Check rate limit status async checkRateLimit() { try { const { data } = await this.octokit.rest.rateLimit.get(); const core = data.resources.core; this.rateLimitInfo = { remaining: core.remaining, resetTime: core.reset }; if (core.remaining === 0) { const resetDate = new Date(core.reset * 1e3); const waitMinutes = Math.ceil((resetDate.getTime() - Date.now()) / (1e3 * 60)); return { canProceed: false, waitMinutes, message: t("github.api.rate.limit.exceeded", { minutes: waitMinutes }) }; } if (core.remaining < 10) { return { canProceed: true, message: t("github.api.rate.limit.warning", { remaining: core.remaining }) }; } return { canProceed: true }; } catch (error) { return { canProceed: true }; } } // Check rate limit before each API call async beforeApiCall() { const rateCheck = await this.checkRateLimit(); if (!rateCheck.canProceed) { new import_obsidian.Notice(rateCheck.message || t("github.api.rate.limit.notice"), 8e3); return false; } if (rateCheck.message && rateCheck.message.includes("\u26A0\uFE0F")) { new import_obsidian.Notice(rateCheck.message, 5e3); } return true; } handleGitHubError(error) { var _a; if (error.status) { switch (error.status) { case 401: return { message: t("github.api.token.invalid"), isRetryable: false }; case 403: if (((_a = error.response) == null ? void 0 : _a.headers) && error.response.headers["x-ratelimit-remaining"] === "0") { const resetTime = error.response.headers["x-ratelimit-reset"]; const resetDate = new Date(parseInt(resetTime) * 1e3); const waitMinutes = Math.ceil((resetDate.getTime() - Date.now()) / (1e3 * 60)); return { message: t("github.api.rate.limit.hourly", { minutes: waitMinutes }), isRetryable: true }; } else { return { message: t("github.api.access.denied"), isRetryable: false }; } case 404: return { message: t("github.api.resource.not.found"), isRetryable: false }; case 409: return { message: t("github.api.file.conflict.detailed"), isRetryable: false }; case 422: return { message: t("github.api.invalid.request"), isRetryable: false }; case 500: case 502: case 503: case 504: return { message: t("github.api.server.error.detailed"), isRetryable: true }; default: return { message: t("github.api.error.with.status", { status: error.status, message: error.message || "Unknown error" }), isRetryable: false }; } } if (error.code === "ENOTFOUND" || error.code === "ECONNREFUSED") { return { message: t("github.api.network.failed"), isRetryable: true }; } if (error.code === "ETIMEDOUT") { return { message: t("github.api.timeout.detailed"), isRetryable: true }; } return { message: t("github.api.operation.failed", { message: error.message || "Unknown error" }), isRetryable: false }; } showErrorNotice(errorInfo) { const notice = new import_obsidian.Notice(errorInfo.message, errorInfo.isRetryable ? 8e3 : 5e3); if (errorInfo.isRetryable) { setTimeout(() => { new import_obsidian.Notice(t("github.api.retry.hint"), 3e3); }, 1e3); } } parseRepositoryUrl(url) { if (!url) { console.error("URL is empty"); return null; } const cleanUrl = url.trim(); let match; match = cleanUrl.match(/^https:\/\/github\.com\/([^\/]+)\/([^\/]+)(?:\/(.*))?$/); if (match) { const result = { owner: match[1], repo: match[2], path: match[3] || "" }; return result; } match = cleanUrl.match(/^([^\/]+)\/([^\/]+)(?:\/(.*))?$/); if (match) { const result = { owner: match[1], repo: match[2], path: match[3] || "" }; return result; } console.error("Unable to parse URL format:", cleanUrl); console.error("Supported formats:"); console.error("1. https://github.com/username/repo/path (standard format)"); console.error("2. username/repo/path (short format)"); return null; } /** * Test GitHub token and repository access */ async testConnection(repositoryUrl) { var _a; const repoInfo = this.parseRepositoryUrl(repositoryUrl); if (!repoInfo) { return { success: false, message: t("github.api.invalid.url.format") }; } if (!await this.beforeApiCall()) { return { success: false, message: t("github.api.rate.limit.exceeded.short") }; } try { const userResponse = await this.octokit.rest.users.getAuthenticated(); const repoResponse = await this.octokit.rest.repos.get({ owner: repoInfo.owner, repo: repoInfo.repo }); if (repoInfo.path) { try { await this.octokit.rest.repos.getContent({ owner: repoInfo.owner, repo: repoInfo.repo, path: repoInfo.path }); } catch (error) { if (error.status !== 404) { throw error; } } } return { success: true, message: t("github.api.connection.test.success", { user: userResponse.data.login, repo: `${repoInfo.owner}/${repoInfo.repo}`, permissions: ((_a = repoResponse.data.permissions) == null ? void 0 : _a.push) ? "read/write" : "read-only" }), repoInfo }; } catch (error) { console.error("GitHub connection test failed:", error); const errorInfo = this.handleGitHubError(error); return { success: false, message: errorInfo.message }; } } async uploadFile(repositoryUrl, filePath, content) { const repoInfo = this.parseRepositoryUrl(repositoryUrl); if (!repoInfo) { return { success: false, message: t("github.api.invalid.url.format") }; } if (!await this.beforeApiCall()) { return { success: false, message: t("github.api.rate.limit.exceeded.short") }; } try { const fullPath = repoInfo.path ? `${repoInfo.path}/${filePath}` : filePath; let sha; try { const { data } = await this.octokit.rest.repos.getContent({ owner: repoInfo.owner, repo: repoInfo.repo, path: fullPath }); if ("sha" in data) { sha = data.sha; } } catch (error) { } await this.octokit.rest.repos.createOrUpdateFileContents({ owner: repoInfo.owner, repo: repoInfo.repo, path: fullPath, message: `Update ${filePath}`, content: Buffer.from(content, "utf8").toString("base64"), sha }); return { success: true, message: t("github.api.file.upload.success") }; } catch (error) { console.error("File upload failed:", error); const errorInfo = this.handleGitHubError(error); this.showErrorNotice(errorInfo); return { success: false, message: errorInfo.message }; } } async downloadFile(repositoryUrl, filePath) { const repoInfo = this.parseRepositoryUrl(repositoryUrl); if (!repoInfo) { return { success: false, message: t("github.api.invalid.url.format") }; } if (!await this.beforeApiCall()) { return { success: false, message: t("github.api.rate.limit.exceeded.short") }; } try { const fullPath = repoInfo.path ? `${repoInfo.path}/${filePath}` : filePath; const { data } = await this.octokit.rest.repos.getContent({ owner: repoInfo.owner, repo: repoInfo.repo, path: fullPath }); if ("content" in data) { const content = Buffer.from(data.content, "base64").toString("utf8"); return { success: true, message: "\u6587\u4EF6\u4E0B\u8F7D\u6210\u529F", content }; } else { return { success: false, message: "\u6307\u5B9A\u8DEF\u5F84\u4E0D\u662F\u6587\u4EF6" }; } } catch (error) { console.error("File download failed:", error); const errorInfo = this.handleGitHubError(error); this.showErrorNotice(errorInfo); return { success: false, message: errorInfo.message }; } } async downloadAllFiles(repositoryUrl) { const repoInfo = this.parseRepositoryUrl(repositoryUrl); if (!repoInfo) { return { success: false, message: t("github.api.invalid.url.format") }; } if (!await this.beforeApiCall()) { return { success: false, message: t("github.api.rate.limit.exceeded.short") }; } try { const files = await this.getAllFilesRecursively(repoInfo.owner, repoInfo.repo, repoInfo.path); const downloadedFiles = []; for (const file of files) { if (file.type === "file") { try { const { data } = await this.octokit.rest.repos.getContent({ owner: repoInfo.owner, repo: repoInfo.repo, path: file.path }); if ("content" in data) { const content = Buffer.from(data.content, "base64").toString("utf8"); const relativePath = repoInfo.path ? file.path.replace(`${repoInfo.path}/`, "") : file.path; downloadedFiles.push({ path: relativePath, content }); } } catch (error) { console.warn(`\u8DF3\u8FC7\u6587\u4EF6 ${file.path}:`, error); } } } return { success: true, message: t("github.api.all.files.download.success"), files: downloadedFiles }; } catch (error) { console.error("Download all files failed:", error); const errorInfo = this.handleGitHubError(error); this.showErrorNotice(errorInfo); return { success: false, message: errorInfo.message }; } } async getAllFilesRecursively(owner, repo, path) { const allFiles = []; try { const { data } = await this.octokit.rest.repos.getContent({ owner, repo, path }); if (Array.isArray(data)) { for (const item of data) { if (item.type === "file") { allFiles.push(item); } else if (item.type === "dir") { const subFiles = await this.getAllFilesRecursively(owner, repo, item.path); allFiles.push(...subFiles); } } } } catch (error) { console.error(`Failed to get directory content ${path}:`, error); } return allFiles; } async getFileLastModified(repositoryUrl, filePath) { var _a, _b; const repoInfo = this.parseRepositoryUrl(repositoryUrl); if (!repoInfo) { return { success: false, exists: false }; } if (this.rateLimitInfo && this.rateLimitInfo.remaining === 0) { return { success: false, exists: false }; } try { const fullPath = repoInfo.path ? `${repoInfo.path}/${filePath}` : filePath; const { data } = await this.octokit.rest.repos.listCommits({ owner: repoInfo.owner, repo: repoInfo.repo, path: fullPath, per_page: 1 }); if (data.length > 0) { const lastCommit = data[0]; return { success: true, exists: true, lastModified: ((_a = lastCommit.commit.committer) == null ? void 0 : _a.date) || ((_b = lastCommit.commit.author) == null ? void 0 : _b.date) }; } else { return { success: true, exists: false }; } } catch (error) { console.error("Failed to get file last modified time:", error); const errorInfo = this.handleGitHubError(error); return { success: false, exists: false }; } } }; // main.ts init_i18n_simple(); // file-cache.ts var FileCacheService = class { // 5 minutes cache validity period constructor() { this.cache = /* @__PURE__ */ new Map(); this.CACHE_KEY = "git-folder-sync-file-cache"; this.DEFAULT_CACHE_AGE = 5 * 60 * 1e3; this.loadCacheFromStorage(); } /** * Load cache from local storage */ loadCacheFromStorage() { try { const stored = localStorage.getItem(this.CACHE_KEY); if (stored) { const cacheData = JSON.parse(stored); this.cache = new Map(Object.entries(cacheData)); console.log(`Loaded ${this.cache.size} file caches`); } } catch (error) { console.error("Failed to load file cache:", error); this.cache.clear(); } } /** * Save cache to local storage */ saveCacheToStorage() { try { const cacheObj = Object.fromEntries(this.cache); localStorage.setItem(this.CACHE_KEY, JSON.stringify(cacheObj)); } catch (error) { console.error("Failed to save file cache:", error); } } /** * Get file cache */ getFileCache(filePath) { const cache = this.cache.get(filePath); if (!cache) { console.log(`File ${filePath} has no cache`); return null; } if (!this.isCacheValid(cache)) { console.log(`File ${filePath} cache has expired`); this.removeFileCache(filePath); return null; } console.log(`File ${filePath} using cache`); return cache; } /** * Set file cache */ setFileCache(filePath, cache) { this.cache.set(filePath, { ...cache, cacheTime: Date.now() }); this.saveCacheToStorage(); console.log(`File ${filePath} cache updated`); } /** * Remove file cache */ removeFileCache(filePath) { if (this.cache.delete(filePath)) { this.saveCacheToStorage(); console.log(`File ${filePath} cache removed`); } } /** * Clear all cache */ clearCache() { this.cache.clear(); localStorage.removeItem(this.CACHE_KEY); } /** * Check if cache is valid */ isCacheValid(cache, maxAge) { const age = maxAge || this.DEFAULT_CACHE_AGE; return Date.now() - cache.cacheTime < age; } /** * Get all cached files */ getAllCachedFiles() { return Array.from(this.cache.values()); } /** * Calculate file content hash */ static calculateContentHash(content) { let hash = 0; for (let i = 0; i < content.length; i++) { const char = content.charCodeAt(i); hash = (hash << 5) - hash + char; hash = hash & hash; } return hash.toString(36); } /** * Check if file has been modified locally */ async checkLocalFileModified(filePath, vault) { try { const cache = this.getFileCache(filePath); if (!cache) return true; const file = vault.getAbstractFileByPath(filePath); if (!file) return true; const content = await vault.read(file); const currentHash = FileCacheService.calculateContentHash(content); return currentHash !== cache.contentHash; } catch (error) { console.error("Failed to check file modification status:", error); return true; } } /** * Update file cache status */ async updateFileCache(filePath, githubPath, lastModified, sha, isPublished, vault) { try { const file = vault.getAbstractFileByPath(filePath); if (!file) return; const content = await vault.read(file); const contentHash = FileCacheService.calculateContentHash(content); const cache = { filePath, githubPath, lastModified, sha, isPublished, isSynced: true, // Newly updated cache is considered synced cacheTime: Date.now(), fileSize: content.length, contentHash }; this.setFileCache(filePath, cache); } catch (error) { console.error("Failed to update file cache:", error); } } /** * Get cache statistics */ getCacheStats() { const allCaches = this.getAllCachedFiles(); const expiredCaches = allCaches.filter((cache) => !this.isCacheValid(cache)); return { totalFiles: allCaches.length, publishedFiles: allCaches.filter((cache) => cache.isPublished).length, syncedFiles: allCaches.filter((cache) => cache.isSynced).length, expiredCaches: expiredCaches.length }; } }; // main.ts init_cos_service(); function debugLog(...args) { if (true) { console.log("[Git Folder Sync]", ...args); } } var GitSyncPlugin = class extends import_obsidian3.Plugin { constructor() { super(...arguments); this.ribbonIconEl = null; this.statusBarEl = null; this.currentFile = null; this.fileModifyTimeout = null; this.isProcessingImagePaste = false; } async onload() { await this.loadSettings(); setLanguage(this.settings.language); this.githubService = new GitHubService(this.settings.githubToken); this.fileCacheService = new FileCacheService(); this.updateRibbonIcon(); this.statusBarEl = this.addStatusBarItem(); this.statusBarEl.addClass("git-sync-status-bar"); this.registerEvent( this.app.workspace.on("active-leaf-change", () => { this.updateStatusBar(); }) ); this.registerEvent( this.app.workspace.on("file-open", (file) => { this.currentFile = file; this.updateStatusBar(); }) ); this.registerEvent( this.app.vault.on("modify", (file) => { if (file.path.endsWith(".md") && this.currentFile && file.path === this.currentFile.path) { debugLog(`Detected file modification: ${file.path}`); if (file instanceof import_obsidian3.TFile) { this.onFileContentModified(file); } } }) ); this.registerDomEvent(document, "paste", this.handlePasteEvent.bind(this), { capture: true }); this.registerDomEvent(document.body, "paste", this.handlePasteEvent.bind(this), { capture: true }); this.addCommand({ id: "show-sync-menu", name: t("command.show.sync.menu"), editorCallback: (editor, view) => { this.showSyncMenu(editor, view); } }); this.registerEvent( this.app.workspace.on("editor-menu", (menu, editor, view) => { menu.addItem((item) => { item.setTitle(t("plugin.name")).setIcon("sync").onClick(async () => { this.showSyncMenu(editor, view); }); }); }) ); this.addSettingTab(new GitSyncSettingTab(this.app, this)); this.updateStatusBar(); } onunload() { if (this.fileModifyTimeout) { clearTimeout(this.fileModifyTimeout); this.fileModifyTimeout = null; } } async loadSettings() { this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); } async saveSettings() { await this.saveData(this.settings); this.githubService.updateToken(this.settings.githubToken); setLanguage(this.settings.language); this.updateRibbonIcon(); } updateRibbonIcon() { if (this.ribbonIconEl) { this.ribbonIconEl.remove(); this.ribbonIconEl = null; } if (this.settings.showRibbonIcon) { this.ribbonIconEl = this.addRibbonIcon("settings", t("settings.title"), (evt) => { this.app.setting.open(); this.app.setting.openTabById(this.manifest.id); }); } } showSyncMenu(editor, view) { var _a; const menu = new import_obsidian3.Menu(); menu.addItem((item) => { item.setTitle(t("actions.sync.current.to.remote")).setIcon("upload").onClick(async () => { await this.syncCurrentFileToRemote(view.file); }); }); menu.addItem((item) => { item.setTitle(t("actions.pull.remote.to.current")).setIcon("download").onClick(async () => { await this.pullRemoteToCurrentFile(view.file); }); }); const rect = (_a = editor.containerEl) == null ? void 0 : _a.getBoundingClientRect(); menu.showAtMouseEvent(rect ? new MouseEvent("click", { clientX: rect.right - 100, clientY: rect.top + 50 }) : new MouseEvent("click")); } async syncCurrentFileToRemote(file) { if (!this.settings.githubToken || !this.settings.repositoryUrl) { new import_obsidian3.Notice(t("settings.github.token.or.repo.not.configured")); return; } try { const content = await this.app.vault.read(file); const result = await this.githubService.uploadFile( this.settings.repositoryUrl, file.path, content ); if (result.success) { new import_obsidian3.Notice(t("sync.success", { filename: file.name })); await this.fileCacheService.updateFileCache( file.path, file.path, new Date().toISOString(), // Use current time as last modified time "", // SHA value can be obtained from upload result later true, // Published this.app.vault ); } else { new import_obsidian3.Notice(t("sync.failed", { message: result.message })); } } catch (error) { console.error("File sync failed:", error); new import_obsidian3.Notice(t("sync.error")); } } async pullRemoteToCurrentFile(file) { if (!this.settings.githubToken || !this.settings.repositoryUrl) { new import_obsidian3.Notice(t("settings.github.token.or.repo.not.configured")); return; } try { const result = await this.githubService.downloadFile( this.settings.repositoryUrl, file.path ); if (result.success && result.content) { await this.app.vault.modify(file, result.content); new import_obsidian3.Notice(t("pull.success", { filename: file.name })); await this.fileCacheService.updateFileCache( file.path, file.path, new Date().toISOString(), // Use current time as last modified time "", // SHA value can be obtained from download result later true, // Published this.app.vault ); } else { new import_obsidian3.Notice(t("pull.failed", { message: result.message })); } } catch (error) { console.error("File pull failed:", error); new import_obsidian3.Notice(t("pull.error")); } } async initializeRepository() { if (!this.isVaultEmpty()) { return { success: false, message: t("vault.not.empty") }; } try { const result = await this.githubService.downloadAllFiles(this.settings.repositoryUrl); if (result.success && result.files) { for (const file of result.files) { await this.createFileInVault(file.path, file.content || ""); await this.fileCacheService.updateFileCache( file.path, file.path, new Date().toISOString(), // Use current time as last modified time "", // SHA value can be obtained from download result later true, // Published this.app.vault ); } setTimeout(() => this.updateStatusBar(), 2e3); return { success: true, message: t("repo.init.success"), filesProcessed: result.files.length }; } return { success: false, message: result.message }; } catch (error) { return { success: false, message: t("repo.init.failed", { error: error.message }) }; } } async forceSyncRemoteToLocal() { try { const result = await this.githubService.downloadAllFiles(this.settings.repositoryUrl); if (result.success && result.files) { for (const file of result.files) { await this.createFileInVault(file.path, file.content || ""); await this.fileCacheService.updateFileCache( file.path, file.path, new Date().toISOString(), // Use current time as last modified time "", // SHA value can be obtained from download result later true, // Published this.app.vault ); } setTimeout(() => this.updateStatusBar(), 2e3); return { success: true, message: t("force.sync.remote.to.local.success"), filesProcessed: result.files.length }; } return { success: false, message: result.message }; } catch (error) { return { success: false, message: t("force.sync.remote.to.local.failed", { error: error.message }) }; } } async forceSyncLocalToRemote() { try { const files = this.getAllVaultFiles(); debugLog("Found files:", files.map((f) => f.path)); if (files.length === 0) { return { success: false, message: t("no.syncable.files.in.vault") }; } let processed = 0; let failed = 0; for (const file of files) { try { const content = await this.app.vault.read(file); const result = await this.githubService.uploadFile( this.settings.repositoryUrl, file.path, content ); if (result.success) { processed++; debugLog(`Successfully synced file: ${file.path}`); await this.fileCacheService.updateFileCache( file.path, file.path, new Date().toISOString(), // Use current time as last modified time "", // SHA value can be obtained from upload result later true, // Published this.app.vault ); } else { failed++; console.error(`File sync failed: ${file.path}`, result.message); } } catch (error) { failed++; console.error(`Failed to read or sync file: ${file.path}`, error); } } const message = failed > 0 ? t("force.sync.local.to.remote.success", { processed, failed }) : t("force.sync.local.to.remote.success.no.failures"); setTimeout(() => this.updateStatusBar(), 2e3); return { success: true, message, filesProcessed: processed }; } catch (error) { console.error("Force sync failed:", error); return { success: false, message: t("force.sync.local.to.remote.failed", { error: error.message }) }; } } isVaultEmpty() { const files = this.app.vault.getFiles(); return files.filter((file) => !file.path.startsWith(this.app.vault.configDir)).length === 0; } getAllVaultFiles() { const allFiles = this.app.vault.getFiles(); debugLog("All files in vault:", allFiles.map((f) => f.path)); const filteredFiles = allFiles.filter((file) => { if (file.path.startsWith(this.app.vault.configDir)) { return false; } if (this.settings.keepLocalImages && this.settings.localImagePath) { const normalizedImagePath = this.settings.localImagePath.replace(/^\/+|\/+$/g, ""); if (normalizedImagePath && file.path.startsWith(normalizedImagePath + "/")) { debugLog(`Excluding file from sync (in image directory): ${file.path}`); return false; } } return true; }); debugLog("Filtered files:", filteredFiles.map((f) => f.path)); return filteredFiles; } async createFileInVault(path, content) { const folderPath = path.substring(0, path.lastIndexOf("/")); if (folderPath && !this.app.vault.getAbstractFileByPath(folderPath)) { await this.app.vault.adapter.mkdir(folderPath); } const existingFile = this.app.vault.getAbstractFileByPath(path); if (existingFile instanceof import_obsidian3.TFile) { await this.app.vault.modify(existingFile, content); } else { await this.app.vault.create(path, content); } } async updateStatusBar() { if (!this.statusBarEl) return; const activeFile = this.app.workspace.getActiveFile(); if (!activeFile || !activeFile.path.endsWith(".md")) { this.statusBarEl.empty(); this.statusBarEl.removeClass("visible"); this.statusBarEl.addClass("hidden"); return; } this.currentFile = activeFile; this.statusBarEl.removeClass("hidden"); this.statusBarEl.addClass("visible"); this.statusBarEl.empty(); const statusText = this.statusBarEl.createEl("span", { cls: "git-sync-status-text", text: t("status.bar.checking") }); const syncButton = this.statusBarEl.createEl("button", { cls: "git-sync-status-button", text: t("status.bar.sync") }); if (this.settings.githubToken && this.settings.repositoryUrl) { try { const cache = this.fileCacheService.getFileCache(activeFile.path); if (cache) { debugLog(`Using cached data to display file status: ${activeFile.path}`); if (cache.isPublished) { const date = new Date(cache.lastModified); let statusMsg = t("status.bar.last.modified", { date: this.formatDate(date) }); if (!cache.isSynced) { statusMsg += ` (${t("status.bar.local.modified")})`; statusText.addClass("modified"); } else { statusMsg += ` (${t("status.bar.synced")})`; statusText.addClass("synced"); } statusText.textContent = statusMsg; } else { statusText.textContent = t("status.bar.not.published"); statusText.addClass("not-published"); } if (!this.fileCacheService.isCacheValid(cache, 4 * 60 * 1e3)) { this.refreshFileCache(activeFile.path).catch(console.error); } } else { debugLog(`No cache, fetching file status from GitHub: ${activeFile.path}`); await this.fetchAndCacheFileStatus(activeFile.path, statusText); } } catch (error) { console.error("Failed to update status bar:", error); statusText.textContent = t("status.bar.check.failed"); } } else { statusText.textContent = t("status.bar.not.configured"); } syncButton.addEventListener("click", (e) => { e.stopPropagation(); this.showSyncMenuForStatusBar(activeFile); }); } /** * Handle file content modification events (with debounce) */ async onFileContentModified(file) { if (this.fileModifyTimeout) { clearTimeout(this.fileModifyTimeout); } this.fileModifyTimeout = setTimeout(async () => { try { const cache = this.fileCacheService.getFileCache(file.path); if (!cache) { this.updateStatusBar(); return; } const content = await this.app.vault.read(file); const currentHash = FileCacheService.calculateContentHash(content); if (currentHash !== cache.contentHash) { debugLog(`File content modified: ${file.path}`); const updatedCache = { ...cache, contentHash: currentHash, isSynced: false, // Mark as not synced cacheTime: Date.now() }; this.fileCacheService.setFileCache(file.path, updatedCache); this.updateStatusBar(); } } catch (error) { console.error("Failed to handle file modification event:", error); } }, 2e3); } /** * Fetch file status from GitHub and cache it */ async fetchAndCacheFileStatus(filePath, statusText) { try { const rateLimitCheck = await this.githubService.checkRateLimit(); if (!rateLimitCheck.canProceed) { statusText.textContent = t("status.bar.rate.limit", { minutes: rateLimitCheck.waitMinutes }); return; } const result = await this.githubService.getFileLastModified( this.settings.repositoryUrl, filePath ); if (result.success) { if (result.exists && result.lastModified) { const date = new Date(result.lastModified); statusText.textContent = t("status.bar.last.modified", { date: this.formatDate(date) }); statusText.addClass("normal"); await this.fileCacheService.updateFileCache( filePath, filePath, // GitHub path same as local path result.lastModified, "", // SHA value temporarily empty, can be obtained from other APIs later true, this.app.vault ); } else { statusText.textContent = t("status.bar.not.published"); statusText.addClass("not-published"); await this.fileCacheService.updateFileCache( filePath, filePath, "", "", false, this.app.vault ); } } else { statusText.textContent = t("status.bar.check.failed"); } } catch (error) { console.error("Failed to fetch file status:", error); statusText.textContent = t("status.bar.check.failed"); } } /** * Asynchronously refresh file cache */ async refreshFileCache(filePath) { try { debugLog(`Asynchronously refreshing file cache: ${filePath}`); const result = await this.githubService.getFileLastModified( this.settings.repositoryUrl, filePath ); if (result.success) { await this.fileCacheService.updateFileCache( filePath, filePath, result.lastModified || "", "", // SHA value temporarily empty result.exists || false, this.app.vault ); debugLog(`File cache refreshed: ${filePath}`); } } catch (error) { console.error("Failed to refresh file cache:", error); } } showSyncMenuForStatusBar(file) { var _a; const menu = new import_obsidian3.Menu(); menu.addItem((item) => { item.setTitle(t("actions.sync.current.to.remote")).setIcon("upload").onClick(async () => { await this.syncCurrentFileToRemote(file); setTimeout(() => this.updateStatusBar(), 1e3); }); }); menu.addItem((item) => { item.setTitle(t("actions.pull.remote.to.current")).setIcon("download").onClick(async () => { await this.pullRemoteToCurrentFile(file); setTimeout(() => this.updateStatusBar(), 1e3); }); }); const rect = (_a = this.statusBarEl) == null ? void 0 : _a.getBoundingClientRect(); menu.showAtMouseEvent(rect ? new MouseEvent("click", { clientX: rect.left, clientY: rect.top - 10 }) : new MouseEvent("click")); } formatDate(date) { const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)); if (diffDays === 0) { return t("date.today"); } else if (diffDays === 1) { return t("date.yesterday"); } else if (diffDays < 7) { return t("date.days.ago", { days: diffDays }); } else { return date.toLocaleDateString("zh-CN"); } } /** * Handle paste events for image upload */ async handlePasteEvent(event) { const activeView = this.app.workspace.getActiveViewOfType(import_obsidian3.MarkdownView); if (!activeView || !this.currentFile) { return; } const clipboardData = event.clipboardData; if (!clipboardData || !clipboardData.files || clipboardData.files.length === 0) { return; } const imageFiles = []; for (let i = 0; i < clipboardData.files.length; i++) { const file = clipboardData.files[i]; if (file.type.startsWith("image/")) { imageFiles.push(file); } } if (imageFiles.length === 0) { return; } if (!this.settings.enableImageProcessing) { return; } event.preventDefault(); event.stopPropagation(); event.stopImmediatePropagation(); this.isProcessingImagePaste = true; const cosConfigured = this.isCosConfigured(); for (const file of imageFiles) { try { if (cosConfigured) { await this.handleImageUpload(file, activeView.editor); } else if (this.settings.keepLocalImages && this.settings.localImagePath) { await this.handleLocalImageOnly(file, activeView.editor); } else { new import_obsidian3.Notice(t("cos.upload.no.config")); } } catch (error) { console.error("Error handling image:", error); new import_obsidian3.Notice(t("cos.upload.failed", { error: error.message })); } } this.isProcessingImagePaste = false; } /** * Get current COS configuration */ getCurrentCosConfig() { return this.settings.cosConfigs[this.settings.cosProvider]; } /** * Update current COS configuration */ updateCurrentCosConfig(updates) { const currentConfig = this.getCurrentCosConfig(); Object.assign(currentConfig, updates); } /** * Clear current COS configuration */ clearCurrentCosConfig() { const emptyConfig = { secretId: "", secretKey: "", bucket: "", endpoint: "", cdnUrl: "", region: "" }; this.settings.cosConfigs[this.settings.cosProvider] = emptyConfig; } /** * Check if COS is properly configured */ isCosConfigured() { const currentConfig = this.getCurrentCosConfig(); const requiredFields = [ currentConfig.secretId, currentConfig.secretKey, currentConfig.bucket, currentConfig.region // Region is required for all providers ]; if (this.settings.cosProvider === "cloudflare") { requiredFields.push(currentConfig.endpoint); } return requiredFields.every((field) => field && field.trim().length > 0); } /** * Handle single image upload */ async handleImageUpload(file, editor) { const timestamp = Date.now(); const extension = file.name.split(".").pop() || "png"; const fileName = `image-${timestamp}.${extension}`; const remotePath = parseImagePath(this.settings.imageUploadPath, { currentFilePath: this.currentFile.path, fileName }); const placeholder = t("cos.paste.placeholder", { filename: fileName }); const cursorPos = editor.getCursor(); editor.replaceRange(placeholder, cursorPos); const uploadNotice = new import_obsidian3.Notice(t("cos.upload.uploading"), 0); try { const currentConfig = this.getCurrentCosConfig(); const cosConfig = { provider: this.settings.cosProvider, secretId: currentConfig.secretId, secretKey: currentConfig.secretKey, bucket: currentConfig.bucket, endpoint: currentConfig.endpoint, cdnUrl: currentConfig.cdnUrl, region: currentConfig.region }; const cosService = new CosService(cosConfig); const uploadResult = await cosService.uploadFile(file, remotePath); if (uploadResult.success && uploadResult.url) { const imageMarkdown = `![${fileName}](${uploadResult.url})`; const currentContent = editor.getValue(); const updatedContent = currentContent.replace(placeholder, imageMarkdown); editor.setValue(updatedContent); if (this.settings.keepLocalImages && this.settings.localImagePath) { await this.saveLocalImageCopy(file, fileName); } uploadNotice.hide(); new import_obsidian3.Notice(t("cos.upload.success")); debugLog("Image uploaded successfully:", uploadResult.url); } else { throw new Error(uploadResult.message || "Upload failed"); } } catch (error) { const currentContent = editor.getValue(); const updatedContent = currentContent.replace(placeholder, ""); editor.setValue(updatedContent); uploadNotice.hide(); new import_obsidian3.Notice(t("cos.upload.failed", { error: error.message })); console.error("Image upload failed:", error); throw error; } } /** * Handle local image storage only (when COS is not configured) */ async handleLocalImageOnly(file, editor) { const timestamp = Date.now(); const extension = file.name.split(".").pop() || "png"; const fileName = `image-${timestamp}.${extension}`; try { const localPath = parseImagePath(this.settings.localImagePath, { currentFilePath: this.currentFile.path, fileName }); const dirPath = localPath.substring(0, localPath.lastIndexOf("/")); if (dirPath) { await this.app.vault.adapter.mkdir(dirPath); } const arrayBuffer = await file.arrayBuffer(); await this.app.vault.createBinary(localPath, arrayBuffer); const imageMarkdown = `![${fileName}](${localPath})`; const cursorPos = editor.getCursor(); editor.replaceRange(imageMarkdown, cursorPos); new import_obsidian3.Notice(t("cos.upload.success")); debugLog("Image saved locally:", localPath); } catch (error) { new import_obsidian3.Notice(t("cos.upload.failed", { error: error.message })); console.error("Local image save failed:", error); } } /** * Save image copy locally if enabled */ async saveLocalImageCopy(file, fileName) { try { const localPath = parseImagePath(this.settings.localImagePath, { currentFilePath: this.currentFile.path, fileName }); const dirPath = localPath.substring(0, localPath.lastIndexOf("/")); if (dirPath) { await this.app.vault.adapter.mkdir(dirPath); } const arrayBuffer = await file.arrayBuffer(); await this.app.vault.createBinary(localPath, arrayBuffer); debugLog("Local image copy saved:", localPath); } catch (error) { console.warn("Failed to save local image copy:", error); } } }; var GitSyncSettingTab = class extends import_obsidian3.PluginSettingTab { constructor(app, plugin) { super(app, plugin); this.plugin = plugin; } display() { const { containerEl } = this; containerEl.empty(); new import_obsidian3.Setting(containerEl).setName(t("settings.title")).setHeading(); new import_obsidian3.Setting(containerEl).setName(t("settings.language.name")).setDesc(t("settings.language.desc")).addDropdown((dropdown) => { const languages = getSupportedLanguages(); languages.forEach((lang) => { dropdown.addOption(lang.value, lang.label); }); dropdown.setValue(this.plugin.settings.language); dropdown.onChange(async (value) => { this.plugin.settings.language = value; await this.plugin.saveSettings(); this.display(); }); }); new import_obsidian3.Setting(containerEl).setName(t("settings.github.token.name")).setDesc(t("settings.github.token.desc")).addText((text) => text.setPlaceholder(t("settings.github.token.placeholder")).setValue(this.plugin.settings.githubToken).onChange(async (value) => { this.plugin.settings.githubToken = value; await this.plugin.saveSettings(); })); let pathInfoEl; new import_obsidian3.Setting(containerEl).setName(t("settings.github.repo.name")).setDesc(t("settings.github.repo.desc")).addText((text) => text.setPlaceholder(t("settings.github.repo.placeholder")).setValue(this.plugin.settings.repositoryUrl).onChange(async (value) => { this.plugin.settings.repositoryUrl = value; this.updatePathInfo(pathInfoEl, value); await this.plugin.saveSettings(); })); pathInfoEl = containerEl.createEl("div", { cls: "setting-item-description git-sync-path-info", text: this.getPathInfoText(this.plugin.settings.repositoryUrl) }); new import_obsidian3.Setting(containerEl).setName(t("settings.test.url.name")).setDesc(t("settings.test.url.desc")).addButton((button) => button.setButtonText(t("settings.test.url.button")).onClick(async () => { if (!this.plugin.settings.repositoryUrl) { new import_obsidian3.Notice(t("notice.url.required")); return; } if (!this.plugin.settings.githubToken) { new import_obsidian3.Notice(t("notice.token.required")); return; } button.setButtonText(t("settings.test.url.loading")); button.setDisabled(true); try { debugLog("=== Testing GitHub Connection ==="); debugLog("Input URL:", this.plugin.settings.repositoryUrl); const testResult = await this.plugin.githubService.testConnection(this.plugin.settings.repositoryUrl); if (testResult.success) { debugLog("Connection test successful:", testResult); new import_obsidian3.Notice(testResult.message, 8e3); } else { debugLog("Connection test failed:", testResult.message); new import_obsidian3.Notice(testResult.message, 6e3); } } catch (error) { debugLog("Connection test error:", error); new import_obsidian3.Notice(t("github.api.operation.failed", { message: error.message }), 6e3); } finally { button.setButtonText(t("settings.test.url.button")); button.setDisabled(false); } })); new import_obsidian3.Setting(containerEl).setName(t("settings.ribbon.name")).setDesc(t("settings.ribbon.desc")).addToggle((toggle) => toggle.setValue(this.plugin.settings.showRibbonIcon).onChange(async (value) => { this.plugin.settings.showRibbonIcon = value; await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName(t("settings.image.section.title")).setHeading(); new import_obsidian3.Setting(containerEl).setName(t("settings.image.enable.name")).setDesc(t("settings.image.enable.desc")).addToggle((toggle) => toggle.setValue(this.plugin.settings.enableImageProcessing).onChange(async (value) => { this.plugin.settings.enableImageProcessing = value; await this.plugin.saveSettings(); this.display(); })); if (this.plugin.settings.enableImageProcessing) { new import_obsidian3.Setting(containerEl).setName(t("settings.cos.provider.section.title")).setHeading(); new import_obsidian3.Setting(containerEl).setName(t("settings.cos.provider.name")).setDesc(t("settings.cos.provider.desc")).addDropdown((dropdown) => { dropdown.addOption("aliyun", t("settings.cos.provider.aliyun")); dropdown.addOption("tencent", t("settings.cos.provider.tencent")); dropdown.addOption("aws", t("settings.cos.provider.aws")); dropdown.addOption("cloudflare", t("settings.cos.provider.cloudflare")); dropdown.setValue(this.plugin.settings.cosProvider); dropdown.onChange(async (value) => { this.plugin.settings.cosProvider = value; await this.plugin.saveSettings(); this.display(); }); }); const currentConfig = this.plugin.getCurrentCosConfig(); new import_obsidian3.Setting(containerEl).setName(t("settings.cos.secret.id.name") + " *").setDesc(t("settings.cos.secret.id.desc")).addText((text) => text.setPlaceholder(t("settings.cos.secret.id.placeholder")).setValue(currentConfig.secretId).onChange(async (value) => { this.plugin.updateCurrentCosConfig({ secretId: value }); await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName(t("settings.cos.secret.key.name") + " *").setDesc(t("settings.cos.secret.key.desc")).addText((text) => text.setPlaceholder(t("settings.cos.secret.key.placeholder")).setValue(currentConfig.secretKey).onChange(async (value) => { this.plugin.updateCurrentCosConfig({ secretKey: value }); await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName(t("settings.cos.bucket.name") + " *").setDesc(t("settings.cos.bucket.desc")).addText((text) => text.setPlaceholder(t("settings.cos.bucket.placeholder")).setValue(currentConfig.bucket).onChange(async (value) => { this.plugin.updateCurrentCosConfig({ bucket: value }); await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName(t("settings.cos.region.name") + " *").setDesc(t("settings.cos.region.desc")).addText((text) => text.setPlaceholder(t("settings.cos.region.placeholder")).setValue(currentConfig.region).onChange(async (value) => { this.plugin.updateCurrentCosConfig({ region: value }); await this.plugin.saveSettings(); })); if (this.plugin.settings.cosProvider === "cloudflare") { new import_obsidian3.Setting(containerEl).setName(t("settings.cos.endpoint.name") + " *").setDesc(t("settings.cos.endpoint.desc")).addText((text) => text.setPlaceholder(t("settings.cos.endpoint.placeholder")).setValue(currentConfig.endpoint).onChange(async (value) => { this.plugin.updateCurrentCosConfig({ endpoint: value }); await this.plugin.saveSettings(); })); } new import_obsidian3.Setting(containerEl).setName(t("settings.cos.cdn.name")).setDesc(t("settings.cos.cdn.desc")).addText((text) => text.setPlaceholder(t("settings.cos.cdn.placeholder")).setValue(currentConfig.cdnUrl).onChange(async (value) => { this.plugin.updateCurrentCosConfig({ cdnUrl: value }); await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName(t("settings.cos.clear.name")).setDesc(t("settings.cos.clear.desc")).addButton((button) => button.setButtonText(t("settings.cos.clear.button")).setWarning().onClick(async () => { this.plugin.clearCurrentCosConfig(); await this.plugin.saveSettings(); new import_obsidian3.Notice(t("settings.cos.clear.success")); this.display(); })); new import_obsidian3.Setting(containerEl).setName(t("settings.cos.test.name")).setDesc(t("settings.cos.test.desc")).addButton((button) => button.setButtonText(t("settings.cos.test.button")).onClick(async () => { const requiredFields = [ currentConfig.secretId, currentConfig.secretKey, currentConfig.bucket, currentConfig.region // Region is required for all providers ]; if (this.plugin.settings.cosProvider === "cloudflare") { requiredFields.push(currentConfig.endpoint); } if (requiredFields.some((field) => !field.trim())) { new import_obsidian3.Notice(t("cos.error.config.invalid")); return; } button.setButtonText(t("settings.cos.test.loading")); button.setDisabled(true); try { const cosConfig = { provider: this.plugin.settings.cosProvider, secretId: currentConfig.secretId, secretKey: currentConfig.secretKey, bucket: currentConfig.bucket, endpoint: currentConfig.endpoint, cdnUrl: currentConfig.cdnUrl, region: currentConfig.region }; const cosService = new (await Promise.resolve().then(() => (init_cos_service(), cos_service_exports))).CosService(cosConfig); const result = await cosService.testConnection(); if (result.success) { new import_obsidian3.Notice(t("cos.test.success")); } else { new import_obsidian3.Notice(t("cos.test.failed", { error: result.message })); } } catch (error) { console.error("COS test error:", error); new import_obsidian3.Notice(t("cos.test.failed", { error: error.message })); } finally { button.setButtonText(t("settings.cos.test.button")); button.setDisabled(false); } })); new import_obsidian3.Setting(containerEl).setName(t("settings.image.upload.section.title")).setHeading(); new import_obsidian3.Setting(containerEl).setName(t("settings.cos.keep.local.name")).setDesc(t("settings.cos.keep.local.desc")).addToggle((toggle) => toggle.setValue(this.plugin.settings.keepLocalImages).onChange(async (value) => { this.plugin.settings.keepLocalImages = value; await this.plugin.saveSettings(); this.display(); })); if (this.plugin.settings.keepLocalImages) { new import_obsidian3.Setting(containerEl).setName(t("settings.cos.local.path.name")).setDesc(t("settings.cos.local.path.desc")).addText((text) => text.setPlaceholder(t("settings.cos.local.path.placeholder")).setValue(this.plugin.settings.localImagePath).onChange(async (value) => { this.plugin.settings.localImagePath = value; await this.plugin.saveSettings(); })); } new import_obsidian3.Setting(containerEl).setName(t("settings.cos.upload.path.name")).setDesc(t("settings.cos.upload.path.desc")).addText((text) => text.setPlaceholder(t("settings.cos.upload.path.placeholder")).setValue(this.plugin.settings.imageUploadPath).onChange(async (value) => { this.plugin.settings.imageUploadPath = value; await this.plugin.saveSettings(); })); } new import_obsidian3.Setting(containerEl).setName(t("settings.danger.zone.title")).setHeading(); new import_obsidian3.Setting(containerEl).setName(t("settings.init.name")).setDesc(t("settings.init.desc")).addButton((button) => { const isVaultEmpty = this.isVaultEmpty(); button.setButtonText(t("settings.init.button")); button.setDisabled(!isVaultEmpty); button.onClick(async () => { if (!this.plugin.settings.githubToken || !this.plugin.settings.repositoryUrl) { new import_obsidian3.Notice(t("notice.config.required")); return; } button.setButtonText(t("settings.init.loading")); button.setDisabled(true); try { const result = await this.plugin.initializeRepository(); if (result.success) { new import_obsidian3.Notice(t("notice.result.with.count", { message: result.message, count: result.filesProcessed })); } else { new import_obsidian3.Notice(result.message); } } catch (error) { new import_obsidian3.Notice(t("notice.init.error")); } finally { button.setButtonText(t("settings.init.button")); button.setDisabled(!this.isVaultEmpty()); } }); if (isVaultEmpty) { button.setCta(); } }); new import_obsidian3.Setting(containerEl).setName(t("settings.sync.remote.to.local.name")).setDesc(t("settings.sync.remote.to.local.desc")).addButton((button) => button.setButtonText(t("settings.sync.remote.to.local.button")).setWarning().onClick(async () => { if (!this.plugin.settings.githubToken || !this.plugin.settings.repositoryUrl) { new import_obsidian3.Notice(t("notice.config.required")); return; } button.setButtonText(t("settings.sync.remote.to.local.loading")); button.setDisabled(true); try { const result = await this.plugin.forceSyncRemoteToLocal(); if (result.success) { new import_obsidian3.Notice(t("notice.result.with.count", { message: result.message, count: result.filesProcessed })); } else { new import_obsidian3.Notice(result.message); } } catch (error) { new import_obsidian3.Notice(t("notice.sync.error")); } finally { button.setButtonText(t("settings.sync.remote.to.local.button")); button.setDisabled(false); } })); new import_obsidian3.Setting(containerEl).setName(t("settings.sync.local.to.remote.name")).setDesc(t("settings.sync.local.to.remote.desc")).addButton((button) => button.setButtonText(t("settings.sync.local.to.remote.button")).setWarning().onClick(async () => { if (!this.plugin.settings.githubToken || !this.plugin.settings.repositoryUrl) { new import_obsidian3.Notice(t("notice.config.required")); return; } button.setButtonText(t("settings.sync.local.to.remote.loading")); button.setDisabled(true); try { const result = await this.plugin.forceSyncLocalToRemote(); if (result.success) { new import_obsidian3.Notice(t("notice.result.with.count", { message: result.message, count: result.filesProcessed })); } else { new import_obsidian3.Notice(result.message); } } catch (error) { new import_obsidian3.Notice(t("notice.sync.error")); } finally { button.setButtonText(t("settings.sync.local.to.remote.button")); button.setDisabled(false); } })); new import_obsidian3.Setting(containerEl).setName(t("settings.clear.cache.name")).setDesc(t("settings.clear.cache.desc")).addButton((button) => button.setButtonText(t("settings.clear.cache.button")).onClick(async () => { try { const stats = this.plugin.fileCacheService.getCacheStats(); this.plugin.fileCacheService.clearCache(); new import_obsidian3.Notice(t("notice.cache.cleared", { count: stats.totalFiles })); } catch (error) { new import_obsidian3.Notice(t("notice.cache.clear.error")); } })); new import_obsidian3.Setting(containerEl).setName(t("settings.sponsor.section.title")).setHeading(); const sponsorSection = containerEl.createEl("div", { cls: "setting-item" }); const sponsorInfo = sponsorSection.createEl("div", { cls: "setting-item-info" }); sponsorInfo.createEl("div", { cls: "setting-item-name", text: t("settings.sponsor.name") }); sponsorInfo.createEl("div", { cls: "setting-item-description", text: t("settings.sponsor.desc") }); const sponsorControl = sponsorSection.createEl("div", { cls: getActualLanguage() === "zh" ? "setting-item-control git-sync-sponsor-control" : "setting-item-control" }); const sponsorButton = sponsorControl.createEl("a", { cls: "mod-cta git-sync-sponsor-button", text: t("settings.sponsor.button"), href: "https://paypal.me/xheldoncao" }); if (getActualLanguage() === "zh") { const chinaSponsorContainer = sponsorControl.createEl("div", { cls: "git-sync-china-sponsor" }); chinaSponsorContainer.createEl("span", { text: t("settings.sponsor.china.label") + ": " }); const chinaLink = chinaSponsorContainer.createEl("a", { text: "https://www.xheldon.com/donate/", href: "https://www.xheldon.com/donate/" }); } } isVaultEmpty() { const files = this.app.vault.getFiles(); return files.filter((file) => !file.path.startsWith(this.app.vault.configDir)).length === 0; } updatePathInfo(el, value) { if (el) { el.empty(); el.createEl("span", { text: this.getPathInfoText(value) }); } } getPathInfoText(value) { if (!value) { return t("path.info.empty"); } const parseResult = this.plugin.githubService.parseRepositoryUrl(value); if (parseResult) { let pathInfo = t("path.info.sync.to", { owner: parseResult.owner, repo: parseResult.repo }); if (parseResult.path) { pathInfo += t("path.info.folder", { path: parseResult.path }); } else { pathInfo += t("path.info.root"); } return pathInfo; } return t("path.info.error"); } }; /*! Bundled license information: is-plain-object/dist/is-plain-object.mjs: (*! * is-plain-object * * Copyright (c) 2014-2017, Jon Schlinkert. * Released under the MIT License. *) */