xheldon_git-folder-sync/main.js
Xheldon 668de78e6f Update plugin ID and name to 'git-folder-sync'
- Changed plugin ID from 'git-sync' to 'git-folder-sync'
- Updated plugin name to 'Git Folder Sync' consistently
- Updated cache key to match new ID
- Bumped version to 1.0.1
- Updated all documentation and i18n strings
2025-07-31 14:54:19 +08:00

5808 lines
231 KiB
JavaScript

/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __esm = (fn, res) => function __init() {
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// node_modules/before-after-hook/lib/register.js
var require_register = __commonJS({
"node_modules/before-after-hook/lib/register.js"(exports, module2) {
module2.exports = register;
function register(state, name, method, options) {
if (typeof method !== "function") {
throw new Error("method for before hook must be a function");
}
if (!options) {
options = {};
}
if (Array.isArray(name)) {
return name.reverse().reduce(function(callback, name2) {
return register.bind(null, state, name2, callback, options);
}, method)();
}
return Promise.resolve().then(function() {
if (!state.registry[name]) {
return method(options);
}
return state.registry[name].reduce(function(method2, registered) {
return registered.hook.bind(null, method2, options);
}, method)();
});
}
}
});
// node_modules/before-after-hook/lib/add.js
var require_add = __commonJS({
"node_modules/before-after-hook/lib/add.js"(exports, module2) {
module2.exports = addHook;
function addHook(state, kind, name, hook2) {
var orig = hook2;
if (!state.registry[name]) {
state.registry[name] = [];
}
if (kind === "before") {
hook2 = function(method, options) {
return Promise.resolve().then(orig.bind(null, options)).then(method.bind(null, options));
};
}
if (kind === "after") {
hook2 = function(method, options) {
var result;
return Promise.resolve().then(method.bind(null, options)).then(function(result_) {
result = result_;
return orig(result, options);
}).then(function() {
return result;
});
};
}
if (kind === "error") {
hook2 = function(method, options) {
return Promise.resolve().then(method.bind(null, options)).catch(function(error) {
return orig(error, options);
});
};
}
state.registry[name].push({
hook: hook2,
orig
});
}
}
});
// node_modules/before-after-hook/lib/remove.js
var require_remove = __commonJS({
"node_modules/before-after-hook/lib/remove.js"(exports, module2) {
module2.exports = removeHook;
function removeHook(state, name, method) {
if (!state.registry[name]) {
return;
}
var index = state.registry[name].map(function(registered) {
return registered.orig;
}).indexOf(method);
if (index === -1) {
return;
}
state.registry[name].splice(index, 1);
}
}
});
// node_modules/before-after-hook/index.js
var require_before_after_hook = __commonJS({
"node_modules/before-after-hook/index.js"(exports, module2) {
var register = require_register();
var addHook = require_add();
var removeHook = require_remove();
var bind = Function.bind;
var bindable = bind.bind(bind);
function bindApi(hook2, state, name) {
var removeHookRef = bindable(removeHook, null).apply(
null,
name ? [state, name] : [state]
);
hook2.api = { remove: removeHookRef };
hook2.remove = removeHookRef;
["before", "error", "after", "wrap"].forEach(function(kind) {
var args = name ? [state, kind, name] : [state, kind];
hook2[kind] = hook2.api[kind] = bindable(addHook, null).apply(null, args);
});
}
function HookSingular() {
var singularHookName = "h";
var singularHookState = {
registry: {}
};
var singularHook = register.bind(null, singularHookState, singularHookName);
bindApi(singularHook, singularHookState, singularHookName);
return singularHook;
}
function HookCollection() {
var state = {
registry: {}
};
var hook2 = register.bind(null, state);
bindApi(hook2, state);
return hook2;
}
var collectionHookDeprecationMessageDisplayed = false;
function Hook() {
if (!collectionHookDeprecationMessageDisplayed) {
console.warn(
'[before-after-hook]: "Hook()" repurposing warning, use "Hook.Collection()". Read more: https://git.io/upgrade-before-after-hook-to-1.4'
);
collectionHookDeprecationMessageDisplayed = true;
}
return HookCollection();
}
Hook.Singular = HookSingular.bind();
Hook.Collection = HookCollection.bind();
module2.exports = Hook;
module2.exports.Hook = Hook;
module2.exports.Singular = Hook.Singular;
module2.exports.Collection = Hook.Collection;
}
});
// node_modules/node-fetch/browser.js
var require_browser = __commonJS({
"node_modules/node-fetch/browser.js"(exports, module2) {
"use strict";
var getGlobal = function() {
if (typeof self !== "undefined") {
return self;
}
if (typeof window !== "undefined") {
return window;
}
if (typeof global !== "undefined") {
return global;
}
throw new Error("unable to locate global object");
};
var globalObject = getGlobal();
module2.exports = exports = globalObject.fetch;
if (globalObject.fetch) {
exports.default = globalObject.fetch.bind(globalObject);
}
exports.Headers = globalObject.Headers;
exports.Request = globalObject.Request;
exports.Response = globalObject.Response;
}
});
// node_modules/wrappy/wrappy.js
var require_wrappy = __commonJS({
"node_modules/wrappy/wrappy.js"(exports, module2) {
module2.exports = wrappy;
function wrappy(fn, cb) {
if (fn && cb)
return wrappy(fn)(cb);
if (typeof fn !== "function")
throw new TypeError("need wrapper function");
Object.keys(fn).forEach(function(k) {
wrapper[k] = fn[k];
});
return wrapper;
function wrapper() {
var args = new Array(arguments.length);
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i];
}
var ret = fn.apply(this, args);
var cb2 = args[args.length - 1];
if (typeof ret === "function" && ret !== cb2) {
Object.keys(cb2).forEach(function(k) {
ret[k] = cb2[k];
});
}
return ret;
}
}
}
});
// node_modules/once/once.js
var require_once = __commonJS({
"node_modules/once/once.js"(exports, module2) {
var wrappy = require_wrappy();
module2.exports = wrappy(once2);
module2.exports.strict = wrappy(onceStrict);
once2.proto = once2(function() {
Object.defineProperty(Function.prototype, "once", {
value: function() {
return once2(this);
},
configurable: true
});
Object.defineProperty(Function.prototype, "onceStrict", {
value: function() {
return onceStrict(this);
},
configurable: true
});
});
function once2(fn) {
var f = function() {
if (f.called)
return f.value;
f.called = true;
return f.value = fn.apply(this, arguments);
};
f.called = false;
return f;
}
function onceStrict(fn) {
var f = function() {
if (f.called)
throw new Error(f.onceError);
f.called = true;
return f.value = fn.apply(this, arguments);
};
var name = fn.name || "Function wrapped with `once`";
f.onceError = name + " shouldn't be called more than once";
f.called = false;
return f;
}
}
});
// i18n-simple.ts
function detectObsidianLanguage() {
var _a, _b, _c, _d, _e, _f;
const obsidianLang = localStorage.getItem("language") || ((_d = (_c = (_b = (_a = window.app) == null ? void 0 : _a.vault) == null ? void 0 : _b.adapter) == null ? void 0 : _c.path) == null ? void 0 : _d.locale) || ((_e = window.moment) == null ? void 0 : _e.locale());
const browserLang = navigator.language || ((_f = navigator.languages) == null ? void 0 : _f[0]) || "en";
if ((obsidianLang == null ? void 0 : obsidianLang.includes("zh")) || browserLang.startsWith("zh")) {
return "zh";
}
return "en";
}
function getActualLanguage() {
if (currentLanguage === "auto") {
return detectObsidianLanguage();
}
return currentLanguage;
}
function setLanguage(language) {
currentLanguage = language;
}
function t(key, params) {
const actualLang = getActualLanguage();
const translation = translations[actualLang][key];
if (!translation) {
console.warn(`Translation missing for key: ${key}`);
return key;
}
if (params) {
return Object.entries(params).reduce((text, [paramKey, paramValue]) => {
return text.replace(new RegExp(`\\{${paramKey}\\}`, "g"), String(paramValue));
}, translation);
}
return translation;
}
function getSupportedLanguages() {
const detectedLang = detectObsidianLanguage();
const detectedLangText = detectedLang === "zh" ? "\u4E2D\u6587" : "English";
const currentLang = getActualLanguage();
const followText = currentLang === "zh" ? "\u8DDF\u968FObsidian" : "Follow Obsidian";
const autoLabel = `${followText} (${detectedLangText})`;
return [
{ value: "auto", label: autoLabel },
{ value: "zh", label: "\u4E2D\u6587" },
{ value: "en", label: "English" }
];
}
var translations, currentLanguage;
var init_i18n_simple = __esm({
"i18n-simple.ts"() {
translations = {
zh: {
// Settings interface
"settings.title": "Git\u540C\u6B65\u8BBE\u7F6E",
"settings.language.name": "\u754C\u9762\u8BED\u8A00",
"settings.language.desc": "\u9009\u62E9\u63D2\u4EF6\u754C\u9762\u663E\u793A\u8BED\u8A00",
"settings.language.auto": "\u8DDF\u968FObsidian",
"settings.github.token.name": "GitHub Personal Token",
"settings.github.token.desc": "\u8F93\u5165\u4F60\u7684GitHub Personal Access Token",
"settings.github.token.placeholder": "ghp_xxxxxxxxxxxx",
"settings.github.repo.name": "GitHub\u4ED3\u5E93\u8DEF\u5F84",
"settings.github.repo.desc": "\u652F\u6301\u4E24\u79CD\u683C\u5F0F\uFF1A\n1. https://github.com/\u7528\u6237\u540D/\u4ED3\u5E93\u540D/\u8DEF\u5F84\n2. \u7528\u6237\u540D/\u4ED3\u5E93\u540D/\u8DEF\u5F84",
"settings.github.repo.placeholder": "https://github.com/Xheldon/git-folder-sync/data/_post",
"settings.ribbon.name": "\u5C06\u63D2\u4EF6\u6309\u94AE\u663E\u793A\u5728\u4FA7\u8FB9\u680F",
"settings.ribbon.desc": "\u5F00\u542F\u540E\uFF0C\u5728\u5DE6\u4FA7\u8FB9\u680F\u663E\u793A\u63D2\u4EF6\u6309\u94AE\uFF0C\u70B9\u51FB\u53EF\u5FEB\u901F\u6253\u5F00\u8BBE\u7F6E\u754C\u9762",
"settings.save.name": "\u4FDD\u5B58\u8BBE\u7F6E",
"settings.save.desc": "\u4FDD\u5B58\u5F53\u524D\u7684\u914D\u7F6E\u8BBE\u7F6E",
"settings.save.button": "\u4FDD\u5B58\u8BBE\u7F6E",
"settings.diagnose.name": "\u8BCA\u65ADVault\u6587\u4EF6",
"settings.diagnose.desc": "\u68C0\u67E5\u5F53\u524DVault\u4E2D\u6709\u54EA\u4E9B\u6587\u4EF6\u53EF\u4EE5\u540C\u6B65",
"settings.diagnose.button": "\u8BCA\u65AD",
"settings.test.url.name": "\u6D4B\u8BD5\u4ED3\u5E93URL",
"settings.test.url.desc": "\u9A8C\u8BC1GitHub\u4ED3\u5E93\u8DEF\u5F84\u683C\u5F0F\u662F\u5426\u6B63\u786E",
"settings.test.url.button": "\u6D4B\u8BD5URL",
"settings.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 Folder Sync Settings",
"settings.language.name": "Interface Language",
"settings.language.desc": "Select the display language for the plugin interface",
"settings.language.auto": "Follow Obsidian",
"settings.github.token.name": "GitHub Personal Token",
"settings.github.token.desc": "Enter your GitHub Personal Access Token",
"settings.github.token.placeholder": "ghp_xxxxxxxxxxxx",
"settings.github.repo.name": "GitHub Repository Path",
"settings.github.repo.desc": "Supports two formats:\n1. https://github.com/username/repo/path\n2. username/repo/path",
"settings.github.repo.placeholder": "https://github.com/Xheldon/git-folder-sync/data/_post",
"settings.ribbon.name": "Show plugin button in sidebar",
"settings.ribbon.desc": "When enabled, display plugin button in left sidebar for quick access to settings",
"settings.save.name": "Save Settings",
"settings.save.desc": "Save current configuration settings",
"settings.save.button": "Save Settings",
"settings.diagnose.name": "Diagnose Vault Files",
"settings.diagnose.desc": "Check which files in current Vault can be synchronized",
"settings.diagnose.button": "Diagnose",
"settings.test.url.name": "Test Repository URL",
"settings.test.url.desc": "Verify if GitHub repository path format is correct",
"settings.test.url.button": "Test URL",
"settings.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 Folder Sync",
"command.show.sync.menu": "Show Sync Menu",
// Test URL results
"test.url.user": "User",
"test.url.repo": "Repo",
"test.url.path": "Path",
"test.url.root": "Root",
// Path info
"path.info.empty": "Enter GitHub repository path to view sync target",
"path.info.sync.to": "Current Vault content will sync to {owner}/{repo} repository",
"path.info.folder": " under {path} folder",
"path.info.root": " under root directory",
"path.info.error": "Path format is incorrect, please use: https://github.com/username/repo/path or username/repo/path",
// COS upload messages
"cos.upload.success": "Image uploaded successfully",
"cos.upload.failed": "Image upload failed: {error}",
"cos.upload.uploading": "Uploading image...",
"cos.upload.no.config": "Image processing is enabled, but cloud storage or local storage path needs to be configured",
"cos.test.success": "COS configuration test successful",
"cos.test.failed": "COS configuration test failed: {error}",
"cos.error.unsupported.provider": "Unsupported cloud storage provider: {provider}",
"cos.error.upload.failed": "Upload failed: {error}",
"cos.error.aliyun.upload.failed": "Aliyun OSS upload failed ({status}): {error}",
"cos.error.tencent.upload.failed": "Tencent COS upload failed ({status}): {error}",
"cos.error.aws.upload.failed": "AWS S3 upload failed ({status}): {error}",
"cos.error.cloudflare.upload.failed": "Cloudflare R2 upload failed ({status}): {error}",
"cos.error.config.invalid": "COS configuration is incomplete, please check settings",
"cos.paste.placeholder": "Uploading {filename}..."
}
};
currentLanguage = "auto";
}
});
// cos-service.ts
var cos_service_exports = {};
__export(cos_service_exports, {
CosService: () => CosService,
parseImagePath: () => parseImagePath
});
function parseImagePath(template, context) {
var _a;
const date = context.date || new Date();
const year = date.getFullYear().toString();
const month = (date.getMonth() + 1).toString().padStart(2, "0");
const day = date.getDate().toString().padStart(2, "0");
const pathParts = context.currentFilePath.split("/");
const fileName = ((_a = pathParts.pop()) == null ? void 0 : _a.replace(/\.[^/.]+$/, "")) || "";
const folderPath = pathParts.join("/");
const folderName = pathParts[pathParts.length - 1] || "";
let result = template.replace(/\{YYYY\}/g, year).replace(/\{MM\}/g, month).replace(/\{DD\}/g, day).replace(/\{PATH\}/g, folderPath).replace(/\{FILENAME\}/g, fileName).replace(/\{FOLDER\}/g, folderName);
if (!result.endsWith("/")) {
result += "/";
}
result += context.fileName;
result = result.replace(/\/+/g, "/").replace(/^\//, "");
return result;
}
var import_obsidian2, CosService;
var init_cos_service = __esm({
"cos-service.ts"() {
init_i18n_simple();
import_obsidian2 = require("obsidian");
CosService = class {
constructor(config) {
this.config = config;
}
/**
* Upload file to COS
*/
async uploadFile(file, remotePath) {
try {
switch (this.config.provider) {
case "aliyun":
return await this.uploadToAliyun(file, remotePath);
case "tencent":
return await this.uploadToTencent(file, remotePath);
case "aws":
return await this.uploadToAWS(file, remotePath);
case "cloudflare":
return await this.uploadToCloudflare(file, remotePath);
default:
return {
success: false,
message: t("cos.error.unsupported.provider", { provider: this.config.provider })
};
}
} catch (error) {
console.error("COS upload error:", error);
return {
success: false,
message: t("cos.error.upload.failed", { error: error.message })
};
}
}
/**
* Test COS configuration
*/
async testConnection() {
try {
const testContent = "test";
const testFile = new File([testContent], "test.txt", { type: "text/plain" });
const testPath = `test-${Date.now()}.txt`;
const result = await this.uploadFile(testFile, testPath);
if (result.success) {
await this.deleteFile(testPath).catch(console.warn);
return {
success: true,
message: t("cos.test.success")
};
}
return result;
} catch (error) {
console.error("COS test connection error:", error);
return {
success: false,
message: t("cos.test.failed", { error: error.message })
};
}
}
/**
* Delete file from COS
*/
async deleteFile(remotePath) {
switch (this.config.provider) {
case "aliyun":
await this.deleteFromAliyun(remotePath);
break;
case "tencent":
await this.deleteFromTencent(remotePath);
break;
case "aws":
await this.deleteFromAWS(remotePath);
break;
case "cloudflare":
await this.deleteFromCloudflare(remotePath);
break;
}
}
/**
* Upload to Aliyun OSS
*/
async uploadToAliyun(file, remotePath) {
const endpoint2 = `oss-${this.config.region}.aliyuncs.com`;
const url = `https://${this.config.bucket}.${endpoint2}/${remotePath}`;
const date = new Date().toUTCString();
const signature = await this.generateAliyunSignature("PUT", remotePath, date, file.type);
const fileBuffer = await file.arrayBuffer();
const response = await (0, import_obsidian2.requestUrl)({
url,
method: "PUT",
headers: {
"Date": date,
"Content-Type": file.type,
"Authorization": `OSS ${this.config.secretId}:${signature}`
},
body: fileBuffer
});
if (response.status >= 200 && response.status < 300) {
const finalUrl = this.config.cdnUrl ? `${this.config.cdnUrl}/${remotePath}` : url;
return {
success: true,
message: t("cos.upload.success"),
url: finalUrl,
key: remotePath
};
} else {
const errorText = response.text;
return {
success: false,
message: t("cos.error.aliyun.upload.failed", {
status: response.status,
error: errorText
})
};
}
}
/**
* Upload to Tencent COS
*/
async uploadToTencent(file, remotePath) {
const url = `https://${this.config.bucket}.cos.${this.config.region}.myqcloud.com/${remotePath}`;
const date = new Date().toUTCString();
const signature = await this.generateTencentSignature("PUT", remotePath, date, file.type);
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 "<environment undetectable>";
}
// 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-folder-sync-file-cache";
this.DEFAULT_CACHE_AGE = 5 * 60 * 1e3;
this.loadCacheFromStorage();
}
/**
* Load cache from local storage
*/
loadCacheFromStorage() {
try {
const stored = localStorage.getItem(this.CACHE_KEY);
if (stored) {
const cacheData = JSON.parse(stored);
this.cache = new Map(Object.entries(cacheData));
console.log(`Loaded ${this.cache.size} file caches`);
}
} catch (error) {
console.error("Failed to load file cache:", error);
this.cache.clear();
}
}
/**
* Save cache to local storage
*/
saveCacheToStorage() {
try {
const cacheObj = Object.fromEntries(this.cache);
localStorage.setItem(this.CACHE_KEY, JSON.stringify(cacheObj));
} catch (error) {
console.error("Failed to save file cache:", error);
}
}
/**
* Get file cache
*/
getFileCache(filePath) {
const cache = this.cache.get(filePath);
if (!cache) {
console.log(`File ${filePath} has no cache`);
return null;
}
if (!this.isCacheValid(cache)) {
console.log(`File ${filePath} cache has expired`);
this.removeFileCache(filePath);
return null;
}
console.log(`File ${filePath} using cache`);
return cache;
}
/**
* Set file cache
*/
setFileCache(filePath, cache) {
this.cache.set(filePath, {
...cache,
cacheTime: Date.now()
});
this.saveCacheToStorage();
console.log(`File ${filePath} cache updated`);
}
/**
* Remove file cache
*/
removeFileCache(filePath) {
if (this.cache.delete(filePath)) {
this.saveCacheToStorage();
console.log(`File ${filePath} cache removed`);
}
}
/**
* Clear all cache
*/
clearCache() {
this.cache.clear();
localStorage.removeItem(this.CACHE_KEY);
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 <https://github.com/jonschlinkert/is-plain-object>
*
* Copyright (c) 2014-2017, Jon Schlinkert.
* Released under the MIT License.
*)
*/