diff --git a/.gitignore b/.gitignore index 7feee4e..01a03d2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ # compiled output -main.js *.js.map # dependencies diff --git a/main.js b/main.js new file mode 100644 index 0000000..48e6eed --- /dev/null +++ b/main.js @@ -0,0 +1,5808 @@ +/* +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-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.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.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", + // 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 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-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.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.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", + // 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 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); + console.log("Tencent COS upload debug:", { + url, + remotePath, + signature: signature.substring(0, 50) + "...", + fileSize: file.size, + fileType: 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) { + console.log("Parsing repository URL:", url); + if (!url) { + console.error("URL is empty"); + return null; + } + const cleanUrl = url.trim(); + console.log("Cleaned URL:", cleanUrl); + let match; + match = cleanUrl.match(/^https:\/\/github\.com\/([^\/]+)\/([^\/]+)(?:\/(.*))?$/); + if (match) { + const result = { + owner: match[1], + repo: match[2], + path: match[3] || "" + }; + console.log("Parse result (standard GitHub URL):", result); + return result; + } + match = cleanUrl.match(/^([^\/]+)\/([^\/]+)(?:\/(.*))?$/); + if (match) { + const result = { + owner: match[1], + repo: match[2], + path: match[3] || "" + }; + console.log("Parse result (short format):", result); + 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; + } + 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-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); + console.log("All file caches cleared"); + } + /** + * 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(); +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) { + console.log(`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(); + if (rect) { + menu.showAtPosition({ x: rect.right - 100, y: rect.top + 50 }); + } else { + menu.showAtMouseEvent(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(); + console.log("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++; + console.log(`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(".obsidian")).length === 0; + } + getAllVaultFiles() { + const allFiles = this.app.vault.getFiles(); + console.log("All files in vault:", allFiles.map((f) => f.path)); + const filteredFiles = allFiles.filter((file) => { + if (file.path.startsWith(".obsidian")) { + return false; + } + if (this.settings.keepLocalImages && this.settings.localImagePath) { + const normalizedImagePath = this.settings.localImagePath.replace(/^\/+|\/+$/g, ""); + if (normalizedImagePath && file.path.startsWith(normalizedImagePath + "/")) { + console.log(`Excluding file from sync (in image directory): ${file.path}`); + return false; + } + } + return true; + }); + console.log("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.createFolder(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.style.display = "none"; + return; + } + this.currentFile = activeFile; + this.statusBarEl.style.display = "flex"; + 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) { + console.log(`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.style.color = "var(--color-orange)"; + } else { + statusMsg += ` (${t("status.bar.synced")})`; + statusText.style.color = "var(--color-green)"; + } + statusText.textContent = statusMsg; + } else { + statusText.textContent = t("status.bar.not.published"); + statusText.style.color = "var(--text-muted)"; + } + if (!this.fileCacheService.isCacheValid(cache, 4 * 60 * 1e3)) { + this.refreshFileCache(activeFile.path).catch(console.error); + } + } else { + console.log(`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) { + console.log(`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.style.color = "var(--text-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.style.color = "var(--text-muted)"; + 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 { + console.log(`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 + ); + console.log(`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(); + if (rect) { + menu.showAtPosition({ x: rect.left, y: rect.top - 10 }); + } + } + 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")); + console.log("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) { + try { + await this.app.vault.createFolder(dirPath); + } catch (error) { + } + } + 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")); + console.log("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) { + try { + await this.app.vault.createFolder(dirPath); + } catch (error) { + } + } + const arrayBuffer = await file.arrayBuffer(); + await this.app.vault.createBinary(localPath, arrayBuffer); + console.log("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(); + containerEl.createEl("h2", { text: t("settings.title") }); + 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; + })); + 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); + })); + 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; + } + console.log("=== Testing Repository URL ==="); + console.log("Input URL:", this.plugin.settings.repositoryUrl); + const testResult = this.plugin.githubService.parseRepositoryUrl(this.plugin.settings.repositoryUrl); + if (testResult) { + console.log("URL parsing successful:", testResult); + new import_obsidian3.Notice(`${t("notice.url.test.success")} +${t("test.url.user")}: ${testResult.owner} +${t("test.url.repo")}: ${testResult.repo} +${t("test.url.path")}: ${testResult.path || t("test.url.root")}`, 6e3); + } else { + console.log("URL parsing failed"); + new import_obsidian3.Notice(t("notice.url.test.failed"), 6e3); + } + })); + 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(); + })); + containerEl.createEl("h2", { + text: t("settings.image.section.title"), + cls: "git-sync-section-title" + }); + 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) { + containerEl.createEl("h3", { + text: t("settings.cos.provider.section.title"), + cls: "git-sync-subsection-title" + }); + 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); + } + })); + containerEl.createEl("h3", { + text: t("settings.image.upload.section.title"), + cls: "git-sync-subsection-title" + }); + 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(); + })); + } + containerEl.createEl("h2", { + text: t("settings.danger.zone.title"), + cls: "danger-zone" + }); + 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")).setDisabled(!isVaultEmpty).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")); + } + })); + containerEl.createEl("h2", { + text: t("settings.sponsor.section.title"), + cls: "sponsor" + }); + 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", + text: t("settings.sponsor.button"), + href: "https://paypal.me/xheldoncao" + }); + sponsorButton.style.textDecoration = "none"; + sponsorButton.style.padding = "6px 12px"; + sponsorButton.style.borderRadius = "3px"; + sponsorButton.style.display = "inline-block"; + 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/" + }); + chinaLink.style.color = "var(--text-accent)"; + chinaLink.style.textDecoration = "none"; + } + } + isVaultEmpty() { + const files = this.app.vault.getFiles(); + return files.filter((file) => !file.path.startsWith(".obsidian")).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. + *) +*/ diff --git a/manifest.json b/manifest.json index 6156153..bac5541 100644 --- a/manifest.json +++ b/manifest.json @@ -1,9 +1,9 @@ { - "id": "git-sync", - "name": "Git Sync", + "id": "obsidian-git-folder-sync", + "name": "Obsidian Git Folder Sync & Image Upload", "version": "1.0.0", "minAppVersion": "0.15.0", - "description": "Synchronize files in your Obsidian Vault with a specified directory in the designated GitHub repository (rather than the entire repository).", + "description": "Synchronize files in your Obsidian Vault with a specified directory in the designated GitHub repository (rather than the entire repository); send your images to cloud storage services.", "author": "Xheldon", "authorUrl": "https://github.com/Xheldon", "fundingUrl": "https://paypal.me/xheldoncao", diff --git a/package.json b/package.json index 6a3b2a0..246ccb9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "git-folder-sync", + "name": "obsidian-git-folder-sync", "version": "1.0.0", - "description": "Synchronize files in your Obsidian Vault with a specified directory in the designated GitHub repository (rather than the entire repository).", + "description": "Synchronize files in your Obsidian Vault with a specified directory in the designated GitHub repository (rather than the entire repository); send your images to cloud storage services.", "main": "main.js", "scripts": { "dev": "node esbuild.config.mjs",