emulate 0.4.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +198 -27
- package/dist/api.d.ts +2 -1
- package/dist/api.js +675 -103
- package/dist/api.js.map +1 -1
- package/dist/chunk-WVQMFHQM.js +83 -0
- package/dist/chunk-WVQMFHQM.js.map +1 -0
- package/dist/{dist-B674PYKV.js → dist-2ZZGNPJI.js} +22 -43
- package/dist/dist-2ZZGNPJI.js.map +1 -0
- package/dist/{dist-RDFBZ5O6.js → dist-CXRPM6BK.js} +211 -48
- package/dist/dist-CXRPM6BK.js.map +1 -0
- package/dist/{dist-VVXVP5EZ.js → dist-DSJSF3GY.js} +551 -91
- package/dist/dist-DSJSF3GY.js.map +1 -0
- package/dist/{dist-RMK3BS5M.js → dist-IFULY5LE.js} +196 -33
- package/dist/dist-IFULY5LE.js.map +1 -0
- package/dist/dist-IRUBHCZU.js +1898 -0
- package/dist/dist-IRUBHCZU.js.map +1 -0
- package/dist/{dist-YOVM5HEY.js → dist-NJJLJT2N.js} +520 -61
- package/dist/dist-NJJLJT2N.js.map +1 -0
- package/dist/dist-OGSAVJ25.js +4874 -0
- package/dist/dist-OGSAVJ25.js.map +1 -0
- package/dist/{dist-H6JYGQM4.js → dist-PO4CL5SJ.js} +271 -158
- package/dist/dist-PO4CL5SJ.js.map +1 -0
- package/dist/{dist-QMOJM6DV.js → dist-R3TNKUIE.js} +238 -55
- package/dist/dist-R3TNKUIE.js.map +1 -0
- package/dist/{dist-6JFNJPUU.js → dist-WACHAAVU.js} +171 -22
- package/dist/dist-WACHAAVU.js.map +1 -0
- package/dist/{dist-OTJZRQ3Q.js → dist-XWWZVLQQ.js} +216 -75
- package/dist/dist-XWWZVLQQ.js.map +1 -0
- package/dist/{dist-6EW7SSOZ.js → dist-ZY5SZSJ2.js} +397 -223
- package/dist/dist-ZY5SZSJ2.js.map +1 -0
- package/dist/fonts/favicon.ico +0 -0
- package/dist/helpers-LXLP3DFE-LBOTATT5.js +17 -0
- package/dist/helpers-LXLP3DFE-LBOTATT5.js.map +1 -0
- package/dist/index.js +812 -117
- package/dist/index.js.map +1 -1
- package/package.json +17 -15
- package/dist/chunk-TEPNEZ63.js +0 -2143
- package/dist/chunk-TEPNEZ63.js.map +0 -1
- package/dist/dist-6EW7SSOZ.js.map +0 -1
- package/dist/dist-6JFNJPUU.js.map +0 -1
- package/dist/dist-B674PYKV.js.map +0 -1
- package/dist/dist-G7WQPZ3Y.js +0 -1287
- package/dist/dist-G7WQPZ3Y.js.map +0 -1
- package/dist/dist-H6JYGQM4.js.map +0 -1
- package/dist/dist-OTJZRQ3Q.js.map +0 -1
- package/dist/dist-QMOJM6DV.js.map +0 -1
- package/dist/dist-RDFBZ5O6.js.map +0 -1
- package/dist/dist-RMK3BS5M.js.map +0 -1
- package/dist/dist-VVXVP5EZ.js.map +0 -1
- package/dist/dist-YOVM5HEY.js.map +0 -1
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import "./chunk-TEPNEZ63.js";
|
|
2
|
-
|
|
3
1
|
// ../@emulators/github/dist/index.js
|
|
4
2
|
import { createHmac } from "crypto";
|
|
5
3
|
import { randomBytes } from "crypto";
|
|
@@ -44,7 +42,10 @@ function getGitHubStore(store) {
|
|
|
44
42
|
checkSuites: store.collection("github.check_suites", ["repo_id", "head_sha"]),
|
|
45
43
|
oauthApps: store.collection("github.oauth_apps", ["client_id"]),
|
|
46
44
|
apps: store.collection("github.apps", ["slug"]),
|
|
47
|
-
appInstallations: store.collection("github.app_installations", [
|
|
45
|
+
appInstallations: store.collection("github.app_installations", [
|
|
46
|
+
"app_id",
|
|
47
|
+
"installation_id"
|
|
48
|
+
]),
|
|
48
49
|
oauthGrants: store.collection("github.oauth_grants", ["user_id", "client_id"])
|
|
49
50
|
};
|
|
50
51
|
}
|
|
@@ -740,6 +741,7 @@ var FONTS = {
|
|
|
740
741
|
"geist-sans.woff2": readFileSync(join(__dirname, "fonts", "geist-sans.woff2")),
|
|
741
742
|
"GeistPixel-Square.woff2": readFileSync(join(__dirname, "fonts", "GeistPixel-Square.woff2"))
|
|
742
743
|
};
|
|
744
|
+
var FAVICON = readFileSync(join(__dirname, "fonts", "favicon.ico"));
|
|
743
745
|
function parsePagination(c) {
|
|
744
746
|
const page = Math.max(1, parseInt(c.req.query("page") ?? "1", 10) || 1);
|
|
745
747
|
const per_page = Math.min(100, Math.max(1, parseInt(c.req.query("per_page") ?? "30", 10) || 30));
|
|
@@ -917,6 +919,132 @@ body{
|
|
|
917
919
|
.app-link-name{font-weight:600;font-size:.875rem;color:#33ff00;}
|
|
918
920
|
.app-link-scopes{font-size:.6875rem;color:#1a8c00;margin-top:1px;}
|
|
919
921
|
.empty{color:#1a8c00;text-align:center;padding:28px 0;font-size:.875rem;}
|
|
922
|
+
|
|
923
|
+
.inspector-layout{max-width:960px;margin:0 auto;padding:28px 20px;}
|
|
924
|
+
.inspector-tabs{display:flex;gap:4px;margin-bottom:20px;}
|
|
925
|
+
.inspector-tabs a{
|
|
926
|
+
padding:7px 16px;border-radius:6px;text-decoration:none;
|
|
927
|
+
font-size:.8125rem;color:#1a8c00;border:1px solid transparent;
|
|
928
|
+
transition:color .15s,border-color .15s;
|
|
929
|
+
}
|
|
930
|
+
.inspector-tabs a:hover{color:#33ff00;}
|
|
931
|
+
.inspector-tabs a.active{color:#33ff00;font-weight:600;border-color:#0a3300;background:#0a3300;}
|
|
932
|
+
.inspector-section{margin-bottom:24px;}
|
|
933
|
+
.inspector-section h2{
|
|
934
|
+
font-family:'Geist Pixel',monospace;
|
|
935
|
+
font-size:1rem;font-weight:600;color:#33ff00;margin-bottom:10px;
|
|
936
|
+
}
|
|
937
|
+
.inspector-section h3{
|
|
938
|
+
font-family:'Geist Pixel',monospace;
|
|
939
|
+
font-size:.875rem;font-weight:600;color:#1a8c00;margin:16px 0 8px;
|
|
940
|
+
}
|
|
941
|
+
.inspector-table{width:100%;border-collapse:collapse;margin-bottom:12px;}
|
|
942
|
+
.inspector-table th,.inspector-table td{
|
|
943
|
+
text-align:left;padding:8px 12px;border-bottom:1px solid #0a3300;
|
|
944
|
+
font-size:.8125rem;
|
|
945
|
+
}
|
|
946
|
+
.inspector-table th{color:#1a8c00;font-weight:600;font-size:.75rem;text-transform:uppercase;letter-spacing:.04em;}
|
|
947
|
+
.inspector-table td{color:#33ff00;}
|
|
948
|
+
.inspector-table tbody tr{transition:background .1s;}
|
|
949
|
+
.inspector-table tbody tr:hover{background:#0a3300;}
|
|
950
|
+
.inspector-empty{color:#1a8c00;text-align:center;padding:20px 0;font-size:.8125rem;}
|
|
951
|
+
|
|
952
|
+
.checkout-layout{
|
|
953
|
+
display:flex;min-height:calc(100vh - 42px);
|
|
954
|
+
}
|
|
955
|
+
.checkout-summary{
|
|
956
|
+
flex:1;background:#020;padding:48px 40px 48px 10%;
|
|
957
|
+
display:flex;flex-direction:column;justify-content:center;
|
|
958
|
+
border-right:1px solid #0a3300;
|
|
959
|
+
}
|
|
960
|
+
.checkout-form-side{
|
|
961
|
+
flex:1;background:#000;padding:48px 10% 48px 40px;
|
|
962
|
+
display:flex;flex-direction:column;justify-content:center;
|
|
963
|
+
}
|
|
964
|
+
.checkout-merchant{
|
|
965
|
+
display:flex;align-items:center;gap:10px;margin-bottom:6px;
|
|
966
|
+
}
|
|
967
|
+
.checkout-merchant-name{
|
|
968
|
+
font-family:'Geist Pixel',monospace;
|
|
969
|
+
font-size:.9375rem;font-weight:600;color:#33ff00;
|
|
970
|
+
}
|
|
971
|
+
.checkout-test-badge{
|
|
972
|
+
font-size:.625rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
|
|
973
|
+
background:#0a3300;color:#1a8c00;padding:2px 8px;border-radius:4px;
|
|
974
|
+
}
|
|
975
|
+
.checkout-total{
|
|
976
|
+
font-family:'Geist Pixel',monospace;
|
|
977
|
+
font-size:2rem;font-weight:700;color:#33ff00;margin:8px 0 28px;
|
|
978
|
+
}
|
|
979
|
+
.checkout-line-item{
|
|
980
|
+
display:flex;align-items:center;gap:14px;padding:14px 0;
|
|
981
|
+
border-bottom:1px solid #0a3300;
|
|
982
|
+
}
|
|
983
|
+
.checkout-line-item:first-child{border-top:1px solid #0a3300;}
|
|
984
|
+
.checkout-item-icon{
|
|
985
|
+
width:42px;height:42px;border-radius:6px;background:#0a3300;
|
|
986
|
+
display:flex;align-items:center;justify-content:center;flex-shrink:0;
|
|
987
|
+
font-family:'Geist Pixel',monospace;font-size:.875rem;font-weight:700;color:#116600;
|
|
988
|
+
}
|
|
989
|
+
.checkout-item-details{flex:1;min-width:0;}
|
|
990
|
+
.checkout-item-name{font-size:.875rem;font-weight:600;color:#33ff00;}
|
|
991
|
+
.checkout-item-qty{font-size:.75rem;color:#1a8c00;margin-top:2px;}
|
|
992
|
+
.checkout-item-price{
|
|
993
|
+
font-size:.875rem;font-weight:600;color:#33ff00;text-align:right;white-space:nowrap;
|
|
994
|
+
}
|
|
995
|
+
.checkout-item-unit{font-size:.6875rem;color:#1a8c00;text-align:right;margin-top:2px;}
|
|
996
|
+
.checkout-totals{margin-top:20px;}
|
|
997
|
+
.checkout-totals-row{
|
|
998
|
+
display:flex;justify-content:space-between;padding:6px 0;
|
|
999
|
+
font-size:.8125rem;color:#1a8c00;
|
|
1000
|
+
}
|
|
1001
|
+
.checkout-totals-row.total{
|
|
1002
|
+
border-top:1px solid #0a3300;margin-top:8px;padding-top:14px;
|
|
1003
|
+
font-size:.9375rem;font-weight:600;color:#33ff00;
|
|
1004
|
+
}
|
|
1005
|
+
.checkout-form-section{margin-bottom:24px;}
|
|
1006
|
+
.checkout-form-label{
|
|
1007
|
+
font-size:.8125rem;font-weight:600;color:#33ff00;margin-bottom:8px;display:block;
|
|
1008
|
+
}
|
|
1009
|
+
.checkout-input{
|
|
1010
|
+
width:100%;padding:10px 12px;border:1px solid #0a3300;border-radius:6px;
|
|
1011
|
+
background:#020;color:#33ff00;font:inherit;font-size:.875rem;
|
|
1012
|
+
transition:border-color .15s;outline:none;
|
|
1013
|
+
}
|
|
1014
|
+
.checkout-input:focus{border-color:#33ff00;}
|
|
1015
|
+
.checkout-input::placeholder{color:#116600;}
|
|
1016
|
+
.checkout-card-box{
|
|
1017
|
+
border:1px solid #0a3300;border-radius:6px;padding:14px;
|
|
1018
|
+
background:#020;
|
|
1019
|
+
}
|
|
1020
|
+
.checkout-card-row{
|
|
1021
|
+
display:flex;gap:12px;margin-top:10px;
|
|
1022
|
+
}
|
|
1023
|
+
.checkout-card-row .checkout-input{flex:1;}
|
|
1024
|
+
.checkout-sim-note{
|
|
1025
|
+
font-size:.6875rem;color:#1a8c00;margin-top:10px;text-align:center;
|
|
1026
|
+
font-style:italic;
|
|
1027
|
+
}
|
|
1028
|
+
.checkout-pay-btn{
|
|
1029
|
+
width:100%;padding:14px;border:none;border-radius:8px;
|
|
1030
|
+
background:#33ff00;color:#000;font:inherit;font-size:.9375rem;font-weight:700;
|
|
1031
|
+
cursor:pointer;transition:background .15s;
|
|
1032
|
+
font-family:'Geist Pixel',monospace;
|
|
1033
|
+
}
|
|
1034
|
+
.checkout-pay-btn:hover{background:#44ff22;}
|
|
1035
|
+
.checkout-cancel{
|
|
1036
|
+
text-align:center;margin-top:14px;
|
|
1037
|
+
}
|
|
1038
|
+
.checkout-cancel a{
|
|
1039
|
+
color:#1a8c00;text-decoration:none;font-size:.8125rem;
|
|
1040
|
+
transition:color .15s;
|
|
1041
|
+
}
|
|
1042
|
+
.checkout-cancel a:hover{color:#33ff00;}
|
|
1043
|
+
@media(max-width:768px){
|
|
1044
|
+
.checkout-layout{flex-direction:column;}
|
|
1045
|
+
.checkout-summary{padding:32px 20px;border-right:none;border-bottom:1px solid #0a3300;}
|
|
1046
|
+
.checkout-form-side{padding:32px 20px;}
|
|
1047
|
+
}
|
|
920
1048
|
`;
|
|
921
1049
|
var POWERED_BY = `<div class="powered-by">Powered by <a href="https://emulate.dev" target="_blank" rel="noopener">emulate</a></div>`;
|
|
922
1050
|
function emuBar(service) {
|
|
@@ -936,6 +1064,7 @@ function head(title) {
|
|
|
936
1064
|
<head>
|
|
937
1065
|
<meta charset="utf-8"/>
|
|
938
1066
|
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
|
1067
|
+
<link rel="icon" href="/_emulate/favicon.ico"/>
|
|
939
1068
|
<title>${escapeHtml(title)} | emulate</title>
|
|
940
1069
|
<style>${CSS}</style>
|
|
941
1070
|
</head>`;
|
|
@@ -1043,9 +1172,7 @@ function canAccessRepo(gh, authUser, repo) {
|
|
|
1043
1172
|
if (!user) return false;
|
|
1044
1173
|
if (repo.owner_type === "User" && repo.owner_id === user.id) return true;
|
|
1045
1174
|
if (repo.owner_type === "Organization" && isOrgMember(gh, user.id, repo.owner_id)) return true;
|
|
1046
|
-
return Boolean(
|
|
1047
|
-
gh.collaborators.findBy("repo_id", repo.id).find((c) => c.user_id === user.id)
|
|
1048
|
-
);
|
|
1175
|
+
return Boolean(gh.collaborators.findBy("repo_id", repo.id).find((c) => c.user_id === user.id));
|
|
1049
1176
|
}
|
|
1050
1177
|
function assertRepoRead(gh, authUser, repo) {
|
|
1051
1178
|
if (canAccessRepo(gh, authUser, repo)) return;
|
|
@@ -1084,9 +1211,7 @@ function assertIssueWrite(gh, authUser, repo) {
|
|
|
1084
1211
|
return user;
|
|
1085
1212
|
}
|
|
1086
1213
|
function listReposForUser(gh, user, type) {
|
|
1087
|
-
const owned = gh.repos.all().filter(
|
|
1088
|
-
(r) => r.owner_id === user.id && r.owner_type === "User"
|
|
1089
|
-
);
|
|
1214
|
+
const owned = gh.repos.all().filter((r) => r.owner_id === user.id && r.owner_type === "User");
|
|
1090
1215
|
const member = gh.collaborators.findBy("user_id", user.id).map((c) => gh.repos.get(c.repo_id)).filter((r) => Boolean(r)).filter((r) => !(r.owner_id === user.id && r.owner_type === "User"));
|
|
1091
1216
|
if (type === "owner") return owned;
|
|
1092
1217
|
if (type === "member") return member;
|
|
@@ -1214,10 +1339,7 @@ function usersRoutes({ app, store, baseUrl }) {
|
|
|
1214
1339
|
});
|
|
1215
1340
|
app.get("/users", (c) => {
|
|
1216
1341
|
const since = Math.max(0, parseInt(c.req.query("since") ?? "0", 10) || 0);
|
|
1217
|
-
const perPage = Math.min(
|
|
1218
|
-
100,
|
|
1219
|
-
Math.max(1, parseInt(c.req.query("per_page") ?? "30", 10) || 30)
|
|
1220
|
-
);
|
|
1342
|
+
const perPage = Math.min(100, Math.max(1, parseInt(c.req.query("per_page") ?? "30", 10) || 30));
|
|
1221
1343
|
const ordered = gh.users.all().filter((u) => u.id > since).sort((a, b) => a.id - b.id);
|
|
1222
1344
|
const page = ordered.slice(0, perPage);
|
|
1223
1345
|
if (page.length === perPage && ordered.length > perPage) {
|
|
@@ -1803,7 +1925,7 @@ function reposRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
1803
1925
|
let ownerType = "User";
|
|
1804
1926
|
let ownerId = user.id;
|
|
1805
1927
|
let fullName = "";
|
|
1806
|
-
|
|
1928
|
+
const forkName = typeof body.name === "string" && body.name.trim() ? validateRepoName(body.name) : parent.name;
|
|
1807
1929
|
if (typeof body.organization === "string" && body.organization.trim()) {
|
|
1808
1930
|
const org = gh.orgs.findOneBy("login", body.organization.trim());
|
|
1809
1931
|
if (!org) throw notFound();
|
|
@@ -1886,9 +2008,7 @@ function reposRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
1886
2008
|
const u = gh.users.get(col.user_id);
|
|
1887
2009
|
if (!u) return null;
|
|
1888
2010
|
return { user: u, permission: col.permission };
|
|
1889
|
-
}).filter(
|
|
1890
|
-
(x) => Boolean(x)
|
|
1891
|
-
).sort((a, b) => a.user.login.localeCompare(b.user.login));
|
|
2011
|
+
}).filter((x) => Boolean(x)).sort((a, b) => a.user.login.localeCompare(b.user.login));
|
|
1892
2012
|
const { page, per_page } = parsePagination(c);
|
|
1893
2013
|
const total = users.length;
|
|
1894
2014
|
const start = (page - 1) * per_page;
|
|
@@ -2009,9 +2129,7 @@ function reposRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
2009
2129
|
const repo = lookupRepo(gh, owner, repoName);
|
|
2010
2130
|
if (!repo) throw notFound();
|
|
2011
2131
|
assertRepoRead(gh, c.get("authUser"), repo);
|
|
2012
|
-
const tags = [...gh.tags.findBy("repo_id", repo.id)].sort(
|
|
2013
|
-
(a, b) => a.tag.localeCompare(b.tag)
|
|
2014
|
-
);
|
|
2132
|
+
const tags = [...gh.tags.findBy("repo_id", repo.id)].sort((a, b) => a.tag.localeCompare(b.tag));
|
|
2015
2133
|
const { page, per_page } = parsePagination(c);
|
|
2016
2134
|
const total = tags.length;
|
|
2017
2135
|
const start = (page - 1) * per_page;
|
|
@@ -2917,9 +3035,7 @@ function checkMergeRequirements(gh, pr) {
|
|
|
2917
3035
|
if (checks && checks.contexts.length > 0) {
|
|
2918
3036
|
const runs = gh.checkRuns.findBy("repo_id", baseRepo.id).filter((r) => r.head_sha === pr.head_sha);
|
|
2919
3037
|
for (const ctx of checks.contexts) {
|
|
2920
|
-
const ok = runs.some(
|
|
2921
|
-
(r) => r.name === ctx && r.status === "completed" && r.conclusion === "success"
|
|
2922
|
-
);
|
|
3038
|
+
const ok = runs.some((r) => r.name === ctx && r.status === "completed" && r.conclusion === "success");
|
|
2923
3039
|
if (!ok) {
|
|
2924
3040
|
throw new ApiError(422, "Required status checks have not succeeded.");
|
|
2925
3041
|
}
|
|
@@ -3353,9 +3469,7 @@ ${commitMessage}` : commitTitle;
|
|
|
3353
3469
|
changes: 1,
|
|
3354
3470
|
blob_url: `${baseUrl}/${repo.full_name}/blob/${pr.head_sha}/${filename}`,
|
|
3355
3471
|
raw_url: `${baseUrl}/${repo.full_name}/raw/${pr.head_sha}/${filename}`,
|
|
3356
|
-
contents_url: `${baseUrl}/repos/${repo.full_name}/contents/${encodeURIComponent(
|
|
3357
|
-
filename
|
|
3358
|
-
)}?ref=${pr.head_ref}`,
|
|
3472
|
+
contents_url: `${baseUrl}/repos/${repo.full_name}/contents/${encodeURIComponent(filename)}?ref=${pr.head_ref}`,
|
|
3359
3473
|
patch: ""
|
|
3360
3474
|
}))
|
|
3361
3475
|
);
|
|
@@ -4088,7 +4202,7 @@ function reviewsRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
4088
4202
|
const pr = findPull3(gh, repo.id, pullNumber);
|
|
4089
4203
|
if (!pr) throw notFound();
|
|
4090
4204
|
const { page, per_page } = parsePagination(c);
|
|
4091
|
-
|
|
4205
|
+
const list = gh.reviews.findBy("repo_id", repo.id).filter((r) => r.pull_number === pullNumber);
|
|
4092
4206
|
list.sort((a, b) => a.id - b.id);
|
|
4093
4207
|
const total = list.length;
|
|
4094
4208
|
setLinkHeader(c, total, page, per_page);
|
|
@@ -4283,9 +4397,7 @@ function reviewsRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
4283
4397
|
if (!review) throw notFound();
|
|
4284
4398
|
const { page, per_page } = parsePagination(c);
|
|
4285
4399
|
const { sort, direction } = parseCommentSort2(c, "asc");
|
|
4286
|
-
let list = gh.comments.findBy("repo_id", repo.id).filter(
|
|
4287
|
-
(x) => x.comment_type === "review" && x.pull_number === pullNumber && x.review_id === reviewId
|
|
4288
|
-
);
|
|
4400
|
+
let list = gh.comments.findBy("repo_id", repo.id).filter((x) => x.comment_type === "review" && x.pull_number === pullNumber && x.review_id === reviewId);
|
|
4289
4401
|
list = sortComments2(list, sort, direction);
|
|
4290
4402
|
const total = list.length;
|
|
4291
4403
|
setLinkHeader(c, total, page, per_page);
|
|
@@ -4340,7 +4452,7 @@ function normalizeColor(raw) {
|
|
|
4340
4452
|
if (typeof raw !== "string" || !raw.trim()) {
|
|
4341
4453
|
throw new ApiError(422, "Validation failed");
|
|
4342
4454
|
}
|
|
4343
|
-
|
|
4455
|
+
const s = raw.trim().replace(/^#/, "");
|
|
4344
4456
|
if (!/^[0-9a-fA-F]{6}$/.test(s)) {
|
|
4345
4457
|
throw new ApiError(422, "Validation failed");
|
|
4346
4458
|
}
|
|
@@ -4426,7 +4538,7 @@ function labelsAndMilestonesRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
4426
4538
|
if (!repo) throw notFound();
|
|
4427
4539
|
assertRepoRead(gh, c.get("authUser"), repo);
|
|
4428
4540
|
const { page, per_page } = parsePagination(c);
|
|
4429
|
-
|
|
4541
|
+
const list = gh.labels.findBy("repo_id", repo.id).slice();
|
|
4430
4542
|
list.sort((a, b) => a.name.localeCompare(b.name));
|
|
4431
4543
|
const total = list.length;
|
|
4432
4544
|
setLinkHeader(c, total, page, per_page);
|
|
@@ -4786,7 +4898,7 @@ function labelsAndMilestonesRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
4786
4898
|
creator_id: actor.id
|
|
4787
4899
|
});
|
|
4788
4900
|
gh.milestones.update(row.id, { node_id: generateNodeId("Milestone", row.id) });
|
|
4789
|
-
|
|
4901
|
+
const m = recalcMilestoneIssueCounts(gh, repo.id, row.id);
|
|
4790
4902
|
const ownerLogin2 = ownerLoginOf(gh, repo);
|
|
4791
4903
|
webhooks.dispatch(
|
|
4792
4904
|
"milestone",
|
|
@@ -4943,7 +5055,7 @@ function labelsAndMilestonesRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
4943
5055
|
if (i.milestone_id !== ms.id) continue;
|
|
4944
5056
|
for (const lid of i.label_ids) labelIdSet.add(lid);
|
|
4945
5057
|
}
|
|
4946
|
-
|
|
5058
|
+
const labels = [...labelIdSet].map((id) => gh.labels.get(id)).filter(Boolean);
|
|
4947
5059
|
labels.sort((a, b) => a.name.localeCompare(b.name));
|
|
4948
5060
|
const total = labels.length;
|
|
4949
5061
|
setLinkHeader(c, total, page, per_page);
|
|
@@ -5424,9 +5536,7 @@ function branchesAndGitRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
5424
5536
|
const repo = lookupRepo(gh, owner, repoName);
|
|
5425
5537
|
if (!repo) throw notFound();
|
|
5426
5538
|
assertRepoRead(gh, c.get("authUser"), repo);
|
|
5427
|
-
let list = [...gh.branches.findBy("repo_id", repo.id)].sort(
|
|
5428
|
-
(a, b) => a.name.localeCompare(b.name)
|
|
5429
|
-
);
|
|
5539
|
+
let list = [...gh.branches.findBy("repo_id", repo.id)].sort((a, b) => a.name.localeCompare(b.name));
|
|
5430
5540
|
const prot = c.req.query("protected");
|
|
5431
5541
|
if (prot === "true") list = list.filter((b) => b.protected);
|
|
5432
5542
|
else if (prot === "false") list = list.filter((b) => !b.protected);
|
|
@@ -5829,12 +5939,7 @@ function branchesAndGitRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
5829
5939
|
object: {
|
|
5830
5940
|
type: tag.object_type,
|
|
5831
5941
|
sha: tag.object_sha,
|
|
5832
|
-
url: objectApiUrl(
|
|
5833
|
-
repo,
|
|
5834
|
-
baseUrl,
|
|
5835
|
-
resolveGitObjectType(gh, repo.id, tag.object_sha),
|
|
5836
|
-
tag.object_sha
|
|
5837
|
-
)
|
|
5942
|
+
url: objectApiUrl(repo, baseUrl, resolveGitObjectType(gh, repo.id, tag.object_sha), tag.object_sha)
|
|
5838
5943
|
},
|
|
5839
5944
|
verification: { verified: false, reason: "unsigned", signature: null, payload: null, verified_at: null }
|
|
5840
5945
|
});
|
|
@@ -5890,12 +5995,7 @@ function branchesAndGitRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
5890
5995
|
object: {
|
|
5891
5996
|
type: saved.object_type,
|
|
5892
5997
|
sha: saved.object_sha,
|
|
5893
|
-
url: objectApiUrl(
|
|
5894
|
-
repo,
|
|
5895
|
-
baseUrl,
|
|
5896
|
-
resolveGitObjectType(gh, repo.id, saved.object_sha),
|
|
5897
|
-
saved.object_sha
|
|
5898
|
-
)
|
|
5998
|
+
url: objectApiUrl(repo, baseUrl, resolveGitObjectType(gh, repo.id, saved.object_sha), saved.object_sha)
|
|
5899
5999
|
},
|
|
5900
6000
|
verification: { verified: false, reason: "unsigned", signature: null, payload: null, verified_at: null }
|
|
5901
6001
|
},
|
|
@@ -6044,10 +6144,7 @@ function orgsAndTeamsRoutes({ app, store, baseUrl }) {
|
|
|
6044
6144
|
const gh = getGitHubStore(store);
|
|
6045
6145
|
app.get("/organizations", (c) => {
|
|
6046
6146
|
const since = Math.max(0, parseInt(c.req.query("since") ?? "0", 10) || 0);
|
|
6047
|
-
const perPage = Math.min(
|
|
6048
|
-
100,
|
|
6049
|
-
Math.max(1, parseInt(c.req.query("per_page") ?? "30", 10) || 30)
|
|
6050
|
-
);
|
|
6147
|
+
const perPage = Math.min(100, Math.max(1, parseInt(c.req.query("per_page") ?? "30", 10) || 30));
|
|
6051
6148
|
const ordered = gh.orgs.all().filter((o) => o.id > since).sort((a, b) => a.id - b.id);
|
|
6052
6149
|
const page = ordered.slice(0, perPage);
|
|
6053
6150
|
if (page.length === perPage && ordered.length > perPage) {
|
|
@@ -6549,9 +6646,7 @@ _Auto-generated release notes (stub)._
|
|
|
6549
6646
|
const repo = lookupRepo(gh, owner, repoName);
|
|
6550
6647
|
if (!repo) throw notFound();
|
|
6551
6648
|
assertRepoRead(gh, c.get("authUser"), repo);
|
|
6552
|
-
const candidates = releasesForRepo(gh, repo.id).filter(
|
|
6553
|
-
(r) => !r.draft && !r.prerelease && r.published_at
|
|
6554
|
-
);
|
|
6649
|
+
const candidates = releasesForRepo(gh, repo.id).filter((r) => !r.draft && !r.prerelease && r.published_at);
|
|
6555
6650
|
if (candidates.length === 0) throw notFound();
|
|
6556
6651
|
candidates.sort((a, b) => {
|
|
6557
6652
|
const pa = a.published_at ?? a.created_at;
|
|
@@ -7762,9 +7857,7 @@ function searchRoutes({ app, store, baseUrl }) {
|
|
|
7762
7857
|
(a, b) => order === "desc" ? b.stargazers_count - a.stargazers_count : a.stargazers_count - b.stargazers_count
|
|
7763
7858
|
);
|
|
7764
7859
|
} else if (sortRaw === "forks") {
|
|
7765
|
-
list.sort(
|
|
7766
|
-
(a, b) => order === "desc" ? b.forks_count - a.forks_count : a.forks_count - b.forks_count
|
|
7767
|
-
);
|
|
7860
|
+
list.sort((a, b) => order === "desc" ? b.forks_count - a.forks_count : a.forks_count - b.forks_count);
|
|
7768
7861
|
} else if (sortRaw === "updated") {
|
|
7769
7862
|
list.sort(
|
|
7770
7863
|
(a, b) => order === "desc" ? b.updated_at.localeCompare(a.updated_at) : a.updated_at.localeCompare(b.updated_at)
|
|
@@ -7816,7 +7909,7 @@ function searchRoutes({ app, store, baseUrl }) {
|
|
|
7816
7909
|
if (body.toLowerCase().includes(t)) s += 1;
|
|
7817
7910
|
return s;
|
|
7818
7911
|
}
|
|
7819
|
-
|
|
7912
|
+
const sorted = [...hits];
|
|
7820
7913
|
if (sortRaw === "created") {
|
|
7821
7914
|
sorted.sort((a, b) => {
|
|
7822
7915
|
const ca = a.kind === "issue" ? a.issue.created_at : a.pr.created_at;
|
|
@@ -7891,7 +7984,7 @@ function searchRoutes({ app, store, baseUrl }) {
|
|
|
7891
7984
|
if (h.o.name?.toLowerCase().includes(text)) s += 1;
|
|
7892
7985
|
return s;
|
|
7893
7986
|
}
|
|
7894
|
-
|
|
7987
|
+
const list = [...hits];
|
|
7895
7988
|
if (sortRaw === "followers") {
|
|
7896
7989
|
list.sort((a, b) => {
|
|
7897
7990
|
const fa = a.kind === "user" ? a.u.followers : a.o.followers;
|
|
@@ -7917,9 +8010,7 @@ function searchRoutes({ app, store, baseUrl }) {
|
|
|
7917
8010
|
const total = list.length;
|
|
7918
8011
|
const slice = list.slice((page - 1) * per_page, (page - 1) * per_page + per_page);
|
|
7919
8012
|
setLinkHeader(c, total, page, per_page);
|
|
7920
|
-
const items = slice.map(
|
|
7921
|
-
(h) => h.kind === "user" ? formatUser(h.u, baseUrl) : formatOrgBrief(h.o, baseUrl)
|
|
7922
|
-
);
|
|
8013
|
+
const items = slice.map((h) => h.kind === "user" ? formatUser(h.u, baseUrl) : formatOrgBrief(h.o, baseUrl));
|
|
7923
8014
|
return c.json({
|
|
7924
8015
|
total_count: total,
|
|
7925
8016
|
incomplete_results: false,
|
|
@@ -8368,7 +8459,13 @@ function formatArtifact(a, repo, gh, baseUrl) {
|
|
|
8368
8459
|
digest: null,
|
|
8369
8460
|
created_at: a.created_at,
|
|
8370
8461
|
expires_at: a.expires_at,
|
|
8371
|
-
workflow_run: run ? {
|
|
8462
|
+
workflow_run: run ? {
|
|
8463
|
+
id: run.id,
|
|
8464
|
+
repository_id: repo.id,
|
|
8465
|
+
head_repository_id: repo.id,
|
|
8466
|
+
head_branch: run.head_branch,
|
|
8467
|
+
head_sha: run.head_sha
|
|
8468
|
+
} : null
|
|
8372
8469
|
};
|
|
8373
8470
|
}
|
|
8374
8471
|
function filterRuns(gh, runs, q) {
|
|
@@ -8486,7 +8583,11 @@ function actionsRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
8486
8583
|
void webhooks.dispatch(
|
|
8487
8584
|
"workflow_run",
|
|
8488
8585
|
"requested",
|
|
8489
|
-
{
|
|
8586
|
+
{
|
|
8587
|
+
workflow_run: formatWorkflowRun(created, repo, gh, baseUrl),
|
|
8588
|
+
repository: formatRepo(repo, gh, baseUrl),
|
|
8589
|
+
sender: formatUser(actor, baseUrl)
|
|
8590
|
+
},
|
|
8490
8591
|
ownerLogin2,
|
|
8491
8592
|
repo.name
|
|
8492
8593
|
);
|
|
@@ -8642,13 +8743,11 @@ function actionsRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
8642
8743
|
const runId = parseInt(c.req.param("run_id"), 10);
|
|
8643
8744
|
const run = gh.workflowRuns.get(runId);
|
|
8644
8745
|
if (!run || run.repo_id !== repo.id) throw notFound();
|
|
8645
|
-
return c.text(
|
|
8646
|
-
`2025-01-01T00:00:00.0000000Z Workflow run ${run.id} logs (stub)
|
|
8746
|
+
return c.text(`2025-01-01T00:00:00.0000000Z Workflow run ${run.id} logs (stub)
|
|
8647
8747
|
${run.head_sha}
|
|
8648
|
-
`,
|
|
8649
|
-
|
|
8650
|
-
|
|
8651
|
-
);
|
|
8748
|
+
`, 200, {
|
|
8749
|
+
"Content-Type": "text/plain; charset=utf-8"
|
|
8750
|
+
});
|
|
8652
8751
|
});
|
|
8653
8752
|
app.get("/repos/:owner/:repo/actions/runs/:run_id/jobs", (c) => {
|
|
8654
8753
|
const owner = c.req.param("owner");
|
|
@@ -8967,15 +9066,7 @@ function parseConclusion(raw) {
|
|
|
8967
9066
|
if (raw === void 0) return void 0;
|
|
8968
9067
|
if (raw === null) return null;
|
|
8969
9068
|
if (typeof raw !== "string") throw new ApiError(422, "Invalid conclusion");
|
|
8970
|
-
const allowed = /* @__PURE__ */ new Set([
|
|
8971
|
-
"success",
|
|
8972
|
-
"failure",
|
|
8973
|
-
"neutral",
|
|
8974
|
-
"cancelled",
|
|
8975
|
-
"skipped",
|
|
8976
|
-
"timed_out",
|
|
8977
|
-
"action_required"
|
|
8978
|
-
]);
|
|
9069
|
+
const allowed = /* @__PURE__ */ new Set(["success", "failure", "neutral", "cancelled", "skipped", "timed_out", "action_required"]);
|
|
8979
9070
|
if (!allowed.has(raw)) throw new ApiError(422, "Invalid conclusion");
|
|
8980
9071
|
return raw;
|
|
8981
9072
|
}
|
|
@@ -9359,7 +9450,7 @@ function checksRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
9359
9450
|
};
|
|
9360
9451
|
}
|
|
9361
9452
|
const nextStatus = patch.status ?? prev.status;
|
|
9362
|
-
|
|
9453
|
+
const nextConclusion = patch.conclusion !== void 0 ? patch.conclusion : prev.conclusion;
|
|
9363
9454
|
if (patch.head_sha && patch.head_sha !== prev.head_sha) {
|
|
9364
9455
|
const newSuite = getOrCreateCheckSuite(gh, repo, patch.head_sha, null);
|
|
9365
9456
|
patch.check_suite_id = newSuite.id;
|
|
@@ -9369,7 +9460,7 @@ function checksRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
9369
9460
|
throw new ApiError(422, "conclusion is required when status is completed");
|
|
9370
9461
|
}
|
|
9371
9462
|
patch.conclusion = nextConclusion;
|
|
9372
|
-
|
|
9463
|
+
const nextCompleted = patch.completed_at !== void 0 ? patch.completed_at : prev.completed_at;
|
|
9373
9464
|
if (!nextCompleted) {
|
|
9374
9465
|
patch.completed_at = timestamp();
|
|
9375
9466
|
}
|
|
@@ -9506,7 +9597,13 @@ function rateLimitRoutes({ app }) {
|
|
|
9506
9597
|
integration_manifest: { limit: 5e3, remaining: 4999, reset, used: 1, resource: "integration_manifest" },
|
|
9507
9598
|
source_import: { limit: 100, remaining: 99, reset, used: 1, resource: "source_import" },
|
|
9508
9599
|
code_scanning_upload: { limit: 500, remaining: 499, reset, used: 1, resource: "code_scanning_upload" },
|
|
9509
|
-
actions_runner_registration: {
|
|
9600
|
+
actions_runner_registration: {
|
|
9601
|
+
limit: 1e4,
|
|
9602
|
+
remaining: 9999,
|
|
9603
|
+
reset,
|
|
9604
|
+
used: 1,
|
|
9605
|
+
resource: "actions_runner_registration"
|
|
9606
|
+
},
|
|
9510
9607
|
scim: { limit: 15e3, remaining: 14999, reset, used: 1, resource: "scim" }
|
|
9511
9608
|
},
|
|
9512
9609
|
rate: rateLimit
|
|
@@ -9582,13 +9679,13 @@ function metaRoutes({ app, baseUrl }) {
|
|
|
9582
9679
|
"+1": `${baseUrl}/emojis/+1.png`,
|
|
9583
9680
|
"-1": `${baseUrl}/emojis/-1.png`,
|
|
9584
9681
|
"100": `${baseUrl}/emojis/100.png`,
|
|
9585
|
-
|
|
9586
|
-
|
|
9587
|
-
|
|
9588
|
-
|
|
9589
|
-
|
|
9590
|
-
|
|
9591
|
-
|
|
9682
|
+
tada: `${baseUrl}/emojis/tada.png`,
|
|
9683
|
+
rocket: `${baseUrl}/emojis/rocket.png`,
|
|
9684
|
+
heart: `${baseUrl}/emojis/heart.png`,
|
|
9685
|
+
eyes: `${baseUrl}/emojis/eyes.png`,
|
|
9686
|
+
thinking: `${baseUrl}/emojis/thinking.png`,
|
|
9687
|
+
thumbsup: `${baseUrl}/emojis/thumbsup.png`,
|
|
9688
|
+
thumbsdown: `${baseUrl}/emojis/thumbsdown.png`
|
|
9592
9689
|
});
|
|
9593
9690
|
});
|
|
9594
9691
|
app.get("/zen", (c) => {
|
|
@@ -9685,9 +9782,15 @@ function oauthRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
9685
9782
|
);
|
|
9686
9783
|
}
|
|
9687
9784
|
if (redirect_uri && !matchesRedirectUri(redirect_uri, oauthApp.redirect_uris)) {
|
|
9688
|
-
console.warn(
|
|
9785
|
+
console.warn(
|
|
9786
|
+
`[OAuth] redirect_uri mismatch: got "${redirect_uri}", registered: ${JSON.stringify(oauthApp.redirect_uris)}`
|
|
9787
|
+
);
|
|
9689
9788
|
return c.html(
|
|
9690
|
-
renderErrorPage(
|
|
9789
|
+
renderErrorPage(
|
|
9790
|
+
"Redirect URI mismatch",
|
|
9791
|
+
"The redirect_uri is not registered for this application.",
|
|
9792
|
+
SERVICE_LABEL
|
|
9793
|
+
),
|
|
9691
9794
|
400
|
|
9692
9795
|
);
|
|
9693
9796
|
}
|
|
@@ -9731,7 +9834,10 @@ function oauthRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
9731
9834
|
clientId: client_id,
|
|
9732
9835
|
created_at: Date.now()
|
|
9733
9836
|
});
|
|
9734
|
-
debug(
|
|
9837
|
+
debug(
|
|
9838
|
+
"github.oauth",
|
|
9839
|
+
`[OAuth callback] generated code: ${code.slice(0, 8)}... for login=${login}, pendingCodes size: ${getPendingCodes(store).size}`
|
|
9840
|
+
);
|
|
9735
9841
|
const sessionId = randomBytes2(24).toString("base64url");
|
|
9736
9842
|
getSessionMap(store).set(sessionId, login);
|
|
9737
9843
|
c.header("Set-Cookie", `_emu_session=${sessionId}; Path=/; HttpOnly; SameSite=Lax`);
|
|
@@ -9746,7 +9852,10 @@ function oauthRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
9746
9852
|
debug("github.oauth", `[OAuth token] Content-Type: ${contentType}`);
|
|
9747
9853
|
debug("github.oauth", `[OAuth token] Accept: ${accept}`);
|
|
9748
9854
|
debug("github.oauth", `[OAuth token] pendingCodes size: ${getPendingCodes(store).size}`);
|
|
9749
|
-
debug(
|
|
9855
|
+
debug(
|
|
9856
|
+
"github.oauth",
|
|
9857
|
+
`[OAuth token] pendingCodes keys: ${[...getPendingCodes(store).keys()].map((k) => k.slice(0, 8) + "...").join(", ")}`
|
|
9858
|
+
);
|
|
9750
9859
|
const rawText = await c.req.text();
|
|
9751
9860
|
debug("github.oauth", `[OAuth token] raw body: ${rawText.slice(0, 500)}`);
|
|
9752
9861
|
let raw;
|
|
@@ -9817,14 +9926,10 @@ function oauthRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
9817
9926
|
}
|
|
9818
9927
|
const oauthApp = gh.oauthApps.findOneBy("client_id", pending.clientId);
|
|
9819
9928
|
if (oauthApp) {
|
|
9820
|
-
const existingGrant = gh.oauthGrants.all().find(
|
|
9821
|
-
(g) => g.user_id === user.id && g.client_id === pending.clientId
|
|
9822
|
-
);
|
|
9929
|
+
const existingGrant = gh.oauthGrants.all().find((g) => g.user_id === user.id && g.client_id === pending.clientId);
|
|
9823
9930
|
const orgAccess = {};
|
|
9824
9931
|
for (const org of gh.orgs.all()) {
|
|
9825
|
-
const isMember = gh.teamMembers.all().some(
|
|
9826
|
-
(tm) => tm.user_id === user.id && gh.teams.get(tm.team_id)?.org_id === org.id
|
|
9827
|
-
);
|
|
9932
|
+
const isMember = gh.teamMembers.all().some((tm) => tm.user_id === user.id && gh.teams.get(tm.team_id)?.org_id === org.id);
|
|
9828
9933
|
if (isMember) orgAccess[org.login] = "granted";
|
|
9829
9934
|
}
|
|
9830
9935
|
if (existingGrant) {
|
|
@@ -9874,19 +9979,19 @@ function oauthRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
9874
9979
|
]);
|
|
9875
9980
|
});
|
|
9876
9981
|
const SCOPE_LABELS = {
|
|
9877
|
-
|
|
9982
|
+
repo: "Full control of private repositories",
|
|
9878
9983
|
"read:user": "Read all user profile data",
|
|
9879
9984
|
"user:email": "Access user email addresses (read-only)",
|
|
9880
|
-
|
|
9881
|
-
|
|
9985
|
+
user: "Full control of user profile",
|
|
9986
|
+
workflow: "Update GitHub action workflows",
|
|
9882
9987
|
"admin:org": "Full control of orgs and teams",
|
|
9883
9988
|
"admin:repo_hook": "Full control of repository hooks",
|
|
9884
9989
|
"read:org": "Read org and team membership",
|
|
9885
9990
|
"write:repo_hook": "Write repository hooks",
|
|
9886
9991
|
"read:repo_hook": "Read repository hooks",
|
|
9887
|
-
|
|
9888
|
-
|
|
9889
|
-
|
|
9992
|
+
delete_repo: "Delete repositories",
|
|
9993
|
+
gist: "Create gists",
|
|
9994
|
+
notifications: "Access notifications",
|
|
9890
9995
|
"write:packages": "Upload packages",
|
|
9891
9996
|
"read:packages": "Download packages",
|
|
9892
9997
|
"admin:gpg_key": "Full control of GPG keys",
|
|
@@ -9900,7 +10005,10 @@ function oauthRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
9900
10005
|
app.get("/settings/applications", (c) => {
|
|
9901
10006
|
const sessionUser = resolveSessionUser(c);
|
|
9902
10007
|
if (!sessionUser) {
|
|
9903
|
-
return c.html(
|
|
10008
|
+
return c.html(
|
|
10009
|
+
renderErrorPage("Unauthorized", "You must be authenticated to view this page.", SERVICE_LABEL),
|
|
10010
|
+
401
|
|
10011
|
+
);
|
|
9904
10012
|
}
|
|
9905
10013
|
const grants = gh.oauthGrants.findBy("user_id", sessionUser.id);
|
|
9906
10014
|
let bodyHtml;
|
|
@@ -9933,12 +10041,13 @@ function oauthRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
9933
10041
|
app.get("/settings/connections/applications/:client_id", (c) => {
|
|
9934
10042
|
const sessionUser = resolveSessionUser(c);
|
|
9935
10043
|
if (!sessionUser) {
|
|
9936
|
-
return c.html(
|
|
10044
|
+
return c.html(
|
|
10045
|
+
renderErrorPage("Unauthorized", "You must be authenticated to view this page.", SERVICE_LABEL),
|
|
10046
|
+
401
|
|
10047
|
+
);
|
|
9937
10048
|
}
|
|
9938
10049
|
const clientId = c.req.param("client_id");
|
|
9939
|
-
const grant = gh.oauthGrants.all().find(
|
|
9940
|
-
(g) => g.user_id === sessionUser.id && g.client_id === clientId
|
|
9941
|
-
);
|
|
10050
|
+
const grant = gh.oauthGrants.all().find((g) => g.user_id === sessionUser.id && g.client_id === clientId);
|
|
9942
10051
|
if (!grant) {
|
|
9943
10052
|
return c.html(renderErrorPage("Not Found", "No authorization found for this application.", SERVICE_LABEL), 404);
|
|
9944
10053
|
}
|
|
@@ -9950,9 +10059,7 @@ function oauthRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
9950
10059
|
month: "long",
|
|
9951
10060
|
day: "numeric"
|
|
9952
10061
|
});
|
|
9953
|
-
const permRows = grant.scopes.map(
|
|
9954
|
-
(s) => `<li><span class="check">✓</span> ${escapeHtml(scopeLabel(s))}</li>`
|
|
9955
|
-
).join("\n");
|
|
10062
|
+
const permRows = grant.scopes.map((s) => `<li><span class="check">✓</span> ${escapeHtml(scopeLabel(s))}</li>`).join("\n");
|
|
9956
10063
|
const orgRows = Object.entries(grant.org_access).map(([org, status]) => {
|
|
9957
10064
|
const letter = escapeHtml((org[0] ?? "?").toUpperCase());
|
|
9958
10065
|
const badgeClass = status === "granted" ? "badge-granted" : status === "denied" ? "badge-denied" : "badge-requested";
|
|
@@ -9996,12 +10103,13 @@ function oauthRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
9996
10103
|
app.post("/settings/connections/applications/:client_id/revoke", (c) => {
|
|
9997
10104
|
const sessionUser = resolveSessionUser(c);
|
|
9998
10105
|
if (!sessionUser) {
|
|
9999
|
-
return c.html(
|
|
10106
|
+
return c.html(
|
|
10107
|
+
renderErrorPage("Unauthorized", "You must be authenticated to perform this action.", SERVICE_LABEL),
|
|
10108
|
+
401
|
|
10109
|
+
);
|
|
10000
10110
|
}
|
|
10001
10111
|
const clientId = c.req.param("client_id");
|
|
10002
|
-
const grant = gh.oauthGrants.all().find(
|
|
10003
|
-
(g) => g.user_id === sessionUser.id && g.client_id === clientId
|
|
10004
|
-
);
|
|
10112
|
+
const grant = gh.oauthGrants.all().find((g) => g.user_id === sessionUser.id && g.client_id === clientId);
|
|
10005
10113
|
if (grant) {
|
|
10006
10114
|
gh.oauthGrants.delete(grant.id);
|
|
10007
10115
|
}
|
|
@@ -10029,10 +10137,13 @@ function appsRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
10029
10137
|
app.get("/app", (c) => {
|
|
10030
10138
|
const authApp = requireApp(c);
|
|
10031
10139
|
if (!authApp) {
|
|
10032
|
-
return c.json(
|
|
10033
|
-
|
|
10034
|
-
|
|
10035
|
-
|
|
10140
|
+
return c.json(
|
|
10141
|
+
{
|
|
10142
|
+
message: "A JSON web token could not be decoded",
|
|
10143
|
+
documentation_url: "https://docs.github.com/rest"
|
|
10144
|
+
},
|
|
10145
|
+
401
|
|
10146
|
+
);
|
|
10036
10147
|
}
|
|
10037
10148
|
const ghApp = gh.apps.all().find((a) => a.app_id === authApp.appId);
|
|
10038
10149
|
if (!ghApp) {
|
|
@@ -10058,29 +10169,31 @@ function appsRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
10058
10169
|
app.get("/app/installations", (c) => {
|
|
10059
10170
|
const authApp = requireApp(c);
|
|
10060
10171
|
if (!authApp) {
|
|
10061
|
-
return c.json(
|
|
10062
|
-
|
|
10063
|
-
|
|
10064
|
-
|
|
10172
|
+
return c.json(
|
|
10173
|
+
{
|
|
10174
|
+
message: "A JSON web token could not be decoded",
|
|
10175
|
+
documentation_url: "https://docs.github.com/rest"
|
|
10176
|
+
},
|
|
10177
|
+
401
|
|
10178
|
+
);
|
|
10065
10179
|
}
|
|
10066
10180
|
const installations = gh.appInstallations.findBy("app_id", authApp.appId);
|
|
10067
10181
|
const ghApp = gh.apps.all().find((a) => a.app_id === authApp.appId);
|
|
10068
|
-
return c.json(
|
|
10069
|
-
installations.map((inst) => formatInstallation(inst, ghApp, baseUrl))
|
|
10070
|
-
);
|
|
10182
|
+
return c.json(installations.map((inst) => formatInstallation(inst, ghApp, baseUrl)));
|
|
10071
10183
|
});
|
|
10072
10184
|
app.get("/app/installations/:installation_id", (c) => {
|
|
10073
10185
|
const authApp = requireApp(c);
|
|
10074
10186
|
if (!authApp) {
|
|
10075
|
-
return c.json(
|
|
10076
|
-
|
|
10077
|
-
|
|
10078
|
-
|
|
10187
|
+
return c.json(
|
|
10188
|
+
{
|
|
10189
|
+
message: "A JSON web token could not be decoded",
|
|
10190
|
+
documentation_url: "https://docs.github.com/rest"
|
|
10191
|
+
},
|
|
10192
|
+
401
|
|
10193
|
+
);
|
|
10079
10194
|
}
|
|
10080
10195
|
const installationId = parseInt(c.req.param("installation_id"), 10);
|
|
10081
|
-
const inst = gh.appInstallations.all().find(
|
|
10082
|
-
(i) => i.installation_id === installationId && i.app_id === authApp.appId
|
|
10083
|
-
);
|
|
10196
|
+
const inst = gh.appInstallations.all().find((i) => i.installation_id === installationId && i.app_id === authApp.appId);
|
|
10084
10197
|
if (!inst) {
|
|
10085
10198
|
return c.json({ message: "Not Found", documentation_url: "https://docs.github.com/rest" }, 404);
|
|
10086
10199
|
}
|
|
@@ -10090,15 +10203,16 @@ function appsRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
10090
10203
|
app.post("/app/installations/:installation_id/access_tokens", async (c) => {
|
|
10091
10204
|
const authApp = requireApp(c);
|
|
10092
10205
|
if (!authApp) {
|
|
10093
|
-
return c.json(
|
|
10094
|
-
|
|
10095
|
-
|
|
10096
|
-
|
|
10206
|
+
return c.json(
|
|
10207
|
+
{
|
|
10208
|
+
message: "A JSON web token could not be decoded",
|
|
10209
|
+
documentation_url: "https://docs.github.com/rest"
|
|
10210
|
+
},
|
|
10211
|
+
401
|
|
10212
|
+
);
|
|
10097
10213
|
}
|
|
10098
10214
|
const installationId = parseInt(c.req.param("installation_id"), 10);
|
|
10099
|
-
const inst = gh.appInstallations.all().find(
|
|
10100
|
-
(i) => i.installation_id === installationId && i.app_id === authApp.appId
|
|
10101
|
-
);
|
|
10215
|
+
const inst = gh.appInstallations.all().find((i) => i.installation_id === installationId && i.app_id === authApp.appId);
|
|
10102
10216
|
if (!inst) {
|
|
10103
10217
|
return c.json({ message: "Not Found", documentation_url: "https://docs.github.com/rest" }, 404);
|
|
10104
10218
|
}
|
|
@@ -10132,13 +10246,16 @@ function appsRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
10132
10246
|
full_name: r.full_name,
|
|
10133
10247
|
private: r.private
|
|
10134
10248
|
}));
|
|
10135
|
-
return c.json(
|
|
10136
|
-
|
|
10137
|
-
|
|
10138
|
-
|
|
10139
|
-
|
|
10140
|
-
|
|
10141
|
-
|
|
10249
|
+
return c.json(
|
|
10250
|
+
{
|
|
10251
|
+
token,
|
|
10252
|
+
expires_at: expiresAt,
|
|
10253
|
+
permissions: requestedPermissions,
|
|
10254
|
+
repository_selection: inst.repository_selection,
|
|
10255
|
+
...inst.repository_selection === "selected" ? { repositories: repos } : {}
|
|
10256
|
+
},
|
|
10257
|
+
201
|
|
10258
|
+
);
|
|
10142
10259
|
});
|
|
10143
10260
|
app.get("/repos/:owner/:repo/installation", (c) => {
|
|
10144
10261
|
const owner = c.req.param("owner");
|
|
@@ -10167,9 +10284,7 @@ function appsRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
10167
10284
|
if (!org) {
|
|
10168
10285
|
return c.json({ message: "Not Found", documentation_url: "https://docs.github.com/rest" }, 404);
|
|
10169
10286
|
}
|
|
10170
|
-
const inst = gh.appInstallations.all().find(
|
|
10171
|
-
(i) => i.account_id === org.id && i.account_type === "Organization"
|
|
10172
|
-
);
|
|
10287
|
+
const inst = gh.appInstallations.all().find((i) => i.account_id === org.id && i.account_type === "Organization");
|
|
10173
10288
|
if (!inst) {
|
|
10174
10289
|
return c.json({ message: "Not Found", documentation_url: "https://docs.github.com/rest" }, 404);
|
|
10175
10290
|
}
|
|
@@ -10182,9 +10297,7 @@ function appsRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
10182
10297
|
if (!user) {
|
|
10183
10298
|
return c.json({ message: "Not Found", documentation_url: "https://docs.github.com/rest" }, 404);
|
|
10184
10299
|
}
|
|
10185
|
-
const inst = gh.appInstallations.all().find(
|
|
10186
|
-
(i) => i.account_id === user.id && i.account_type === "User"
|
|
10187
|
-
);
|
|
10300
|
+
const inst = gh.appInstallations.all().find((i) => i.account_id === user.id && i.account_type === "User");
|
|
10188
10301
|
if (!inst) {
|
|
10189
10302
|
return c.json({ message: "Not Found", documentation_url: "https://docs.github.com/rest" }, 404);
|
|
10190
10303
|
}
|
|
@@ -10583,4 +10696,4 @@ export {
|
|
|
10583
10696
|
githubPlugin,
|
|
10584
10697
|
seedFromConfig
|
|
10585
10698
|
};
|
|
10586
|
-
//# sourceMappingURL=dist-
|
|
10699
|
+
//# sourceMappingURL=dist-PO4CL5SJ.js.map
|