@emulators/github 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/dist/fonts/favicon.ico +0 -0
- package/dist/index.js +270 -157
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -37,7 +37,10 @@ function getGitHubStore(store) {
|
|
|
37
37
|
checkSuites: store.collection("github.check_suites", ["repo_id", "head_sha"]),
|
|
38
38
|
oauthApps: store.collection("github.oauth_apps", ["client_id"]),
|
|
39
39
|
apps: store.collection("github.apps", ["slug"]),
|
|
40
|
-
appInstallations: store.collection("github.app_installations", [
|
|
40
|
+
appInstallations: store.collection("github.app_installations", [
|
|
41
|
+
"app_id",
|
|
42
|
+
"installation_id"
|
|
43
|
+
]),
|
|
41
44
|
oauthGrants: store.collection("github.oauth_grants", ["user_id", "client_id"])
|
|
42
45
|
};
|
|
43
46
|
}
|
|
@@ -690,8 +693,6 @@ function getNextMilestoneNumber(store, repoId) {
|
|
|
690
693
|
}
|
|
691
694
|
|
|
692
695
|
// ../core/dist/index.js
|
|
693
|
-
import { Hono } from "hono";
|
|
694
|
-
import { cors } from "hono/cors";
|
|
695
696
|
import { readFileSync } from "fs";
|
|
696
697
|
import { fileURLToPath } from "url";
|
|
697
698
|
import { dirname, join } from "path";
|
|
@@ -744,6 +745,7 @@ var FONTS = {
|
|
|
744
745
|
"geist-sans.woff2": readFileSync(join(__dirname, "fonts", "geist-sans.woff2")),
|
|
745
746
|
"GeistPixel-Square.woff2": readFileSync(join(__dirname, "fonts", "GeistPixel-Square.woff2"))
|
|
746
747
|
};
|
|
748
|
+
var FAVICON = readFileSync(join(__dirname, "fonts", "favicon.ico"));
|
|
747
749
|
function parsePagination(c) {
|
|
748
750
|
const page = Math.max(1, parseInt(c.req.query("page") ?? "1", 10) || 1);
|
|
749
751
|
const per_page = Math.min(100, Math.max(1, parseInt(c.req.query("per_page") ?? "30", 10) || 30));
|
|
@@ -921,6 +923,132 @@ body{
|
|
|
921
923
|
.app-link-name{font-weight:600;font-size:.875rem;color:#33ff00;}
|
|
922
924
|
.app-link-scopes{font-size:.6875rem;color:#1a8c00;margin-top:1px;}
|
|
923
925
|
.empty{color:#1a8c00;text-align:center;padding:28px 0;font-size:.875rem;}
|
|
926
|
+
|
|
927
|
+
.inspector-layout{max-width:960px;margin:0 auto;padding:28px 20px;}
|
|
928
|
+
.inspector-tabs{display:flex;gap:4px;margin-bottom:20px;}
|
|
929
|
+
.inspector-tabs a{
|
|
930
|
+
padding:7px 16px;border-radius:6px;text-decoration:none;
|
|
931
|
+
font-size:.8125rem;color:#1a8c00;border:1px solid transparent;
|
|
932
|
+
transition:color .15s,border-color .15s;
|
|
933
|
+
}
|
|
934
|
+
.inspector-tabs a:hover{color:#33ff00;}
|
|
935
|
+
.inspector-tabs a.active{color:#33ff00;font-weight:600;border-color:#0a3300;background:#0a3300;}
|
|
936
|
+
.inspector-section{margin-bottom:24px;}
|
|
937
|
+
.inspector-section h2{
|
|
938
|
+
font-family:'Geist Pixel',monospace;
|
|
939
|
+
font-size:1rem;font-weight:600;color:#33ff00;margin-bottom:10px;
|
|
940
|
+
}
|
|
941
|
+
.inspector-section h3{
|
|
942
|
+
font-family:'Geist Pixel',monospace;
|
|
943
|
+
font-size:.875rem;font-weight:600;color:#1a8c00;margin:16px 0 8px;
|
|
944
|
+
}
|
|
945
|
+
.inspector-table{width:100%;border-collapse:collapse;margin-bottom:12px;}
|
|
946
|
+
.inspector-table th,.inspector-table td{
|
|
947
|
+
text-align:left;padding:8px 12px;border-bottom:1px solid #0a3300;
|
|
948
|
+
font-size:.8125rem;
|
|
949
|
+
}
|
|
950
|
+
.inspector-table th{color:#1a8c00;font-weight:600;font-size:.75rem;text-transform:uppercase;letter-spacing:.04em;}
|
|
951
|
+
.inspector-table td{color:#33ff00;}
|
|
952
|
+
.inspector-table tbody tr{transition:background .1s;}
|
|
953
|
+
.inspector-table tbody tr:hover{background:#0a3300;}
|
|
954
|
+
.inspector-empty{color:#1a8c00;text-align:center;padding:20px 0;font-size:.8125rem;}
|
|
955
|
+
|
|
956
|
+
.checkout-layout{
|
|
957
|
+
display:flex;min-height:calc(100vh - 42px);
|
|
958
|
+
}
|
|
959
|
+
.checkout-summary{
|
|
960
|
+
flex:1;background:#020;padding:48px 40px 48px 10%;
|
|
961
|
+
display:flex;flex-direction:column;justify-content:center;
|
|
962
|
+
border-right:1px solid #0a3300;
|
|
963
|
+
}
|
|
964
|
+
.checkout-form-side{
|
|
965
|
+
flex:1;background:#000;padding:48px 10% 48px 40px;
|
|
966
|
+
display:flex;flex-direction:column;justify-content:center;
|
|
967
|
+
}
|
|
968
|
+
.checkout-merchant{
|
|
969
|
+
display:flex;align-items:center;gap:10px;margin-bottom:6px;
|
|
970
|
+
}
|
|
971
|
+
.checkout-merchant-name{
|
|
972
|
+
font-family:'Geist Pixel',monospace;
|
|
973
|
+
font-size:.9375rem;font-weight:600;color:#33ff00;
|
|
974
|
+
}
|
|
975
|
+
.checkout-test-badge{
|
|
976
|
+
font-size:.625rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
|
|
977
|
+
background:#0a3300;color:#1a8c00;padding:2px 8px;border-radius:4px;
|
|
978
|
+
}
|
|
979
|
+
.checkout-total{
|
|
980
|
+
font-family:'Geist Pixel',monospace;
|
|
981
|
+
font-size:2rem;font-weight:700;color:#33ff00;margin:8px 0 28px;
|
|
982
|
+
}
|
|
983
|
+
.checkout-line-item{
|
|
984
|
+
display:flex;align-items:center;gap:14px;padding:14px 0;
|
|
985
|
+
border-bottom:1px solid #0a3300;
|
|
986
|
+
}
|
|
987
|
+
.checkout-line-item:first-child{border-top:1px solid #0a3300;}
|
|
988
|
+
.checkout-item-icon{
|
|
989
|
+
width:42px;height:42px;border-radius:6px;background:#0a3300;
|
|
990
|
+
display:flex;align-items:center;justify-content:center;flex-shrink:0;
|
|
991
|
+
font-family:'Geist Pixel',monospace;font-size:.875rem;font-weight:700;color:#116600;
|
|
992
|
+
}
|
|
993
|
+
.checkout-item-details{flex:1;min-width:0;}
|
|
994
|
+
.checkout-item-name{font-size:.875rem;font-weight:600;color:#33ff00;}
|
|
995
|
+
.checkout-item-qty{font-size:.75rem;color:#1a8c00;margin-top:2px;}
|
|
996
|
+
.checkout-item-price{
|
|
997
|
+
font-size:.875rem;font-weight:600;color:#33ff00;text-align:right;white-space:nowrap;
|
|
998
|
+
}
|
|
999
|
+
.checkout-item-unit{font-size:.6875rem;color:#1a8c00;text-align:right;margin-top:2px;}
|
|
1000
|
+
.checkout-totals{margin-top:20px;}
|
|
1001
|
+
.checkout-totals-row{
|
|
1002
|
+
display:flex;justify-content:space-between;padding:6px 0;
|
|
1003
|
+
font-size:.8125rem;color:#1a8c00;
|
|
1004
|
+
}
|
|
1005
|
+
.checkout-totals-row.total{
|
|
1006
|
+
border-top:1px solid #0a3300;margin-top:8px;padding-top:14px;
|
|
1007
|
+
font-size:.9375rem;font-weight:600;color:#33ff00;
|
|
1008
|
+
}
|
|
1009
|
+
.checkout-form-section{margin-bottom:24px;}
|
|
1010
|
+
.checkout-form-label{
|
|
1011
|
+
font-size:.8125rem;font-weight:600;color:#33ff00;margin-bottom:8px;display:block;
|
|
1012
|
+
}
|
|
1013
|
+
.checkout-input{
|
|
1014
|
+
width:100%;padding:10px 12px;border:1px solid #0a3300;border-radius:6px;
|
|
1015
|
+
background:#020;color:#33ff00;font:inherit;font-size:.875rem;
|
|
1016
|
+
transition:border-color .15s;outline:none;
|
|
1017
|
+
}
|
|
1018
|
+
.checkout-input:focus{border-color:#33ff00;}
|
|
1019
|
+
.checkout-input::placeholder{color:#116600;}
|
|
1020
|
+
.checkout-card-box{
|
|
1021
|
+
border:1px solid #0a3300;border-radius:6px;padding:14px;
|
|
1022
|
+
background:#020;
|
|
1023
|
+
}
|
|
1024
|
+
.checkout-card-row{
|
|
1025
|
+
display:flex;gap:12px;margin-top:10px;
|
|
1026
|
+
}
|
|
1027
|
+
.checkout-card-row .checkout-input{flex:1;}
|
|
1028
|
+
.checkout-sim-note{
|
|
1029
|
+
font-size:.6875rem;color:#1a8c00;margin-top:10px;text-align:center;
|
|
1030
|
+
font-style:italic;
|
|
1031
|
+
}
|
|
1032
|
+
.checkout-pay-btn{
|
|
1033
|
+
width:100%;padding:14px;border:none;border-radius:8px;
|
|
1034
|
+
background:#33ff00;color:#000;font:inherit;font-size:.9375rem;font-weight:700;
|
|
1035
|
+
cursor:pointer;transition:background .15s;
|
|
1036
|
+
font-family:'Geist Pixel',monospace;
|
|
1037
|
+
}
|
|
1038
|
+
.checkout-pay-btn:hover{background:#44ff22;}
|
|
1039
|
+
.checkout-cancel{
|
|
1040
|
+
text-align:center;margin-top:14px;
|
|
1041
|
+
}
|
|
1042
|
+
.checkout-cancel a{
|
|
1043
|
+
color:#1a8c00;text-decoration:none;font-size:.8125rem;
|
|
1044
|
+
transition:color .15s;
|
|
1045
|
+
}
|
|
1046
|
+
.checkout-cancel a:hover{color:#33ff00;}
|
|
1047
|
+
@media(max-width:768px){
|
|
1048
|
+
.checkout-layout{flex-direction:column;}
|
|
1049
|
+
.checkout-summary{padding:32px 20px;border-right:none;border-bottom:1px solid #0a3300;}
|
|
1050
|
+
.checkout-form-side{padding:32px 20px;}
|
|
1051
|
+
}
|
|
924
1052
|
`;
|
|
925
1053
|
var POWERED_BY = `<div class="powered-by">Powered by <a href="https://emulate.dev" target="_blank" rel="noopener">emulate</a></div>`;
|
|
926
1054
|
function emuBar(service) {
|
|
@@ -940,6 +1068,7 @@ function head(title) {
|
|
|
940
1068
|
<head>
|
|
941
1069
|
<meta charset="utf-8"/>
|
|
942
1070
|
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
|
1071
|
+
<link rel="icon" href="/_emulate/favicon.ico"/>
|
|
943
1072
|
<title>${escapeHtml(title)} | emulate</title>
|
|
944
1073
|
<style>${CSS}</style>
|
|
945
1074
|
</head>`;
|
|
@@ -1049,9 +1178,7 @@ function canAccessRepo(gh, authUser, repo) {
|
|
|
1049
1178
|
if (!user) return false;
|
|
1050
1179
|
if (repo.owner_type === "User" && repo.owner_id === user.id) return true;
|
|
1051
1180
|
if (repo.owner_type === "Organization" && isOrgMember(gh, user.id, repo.owner_id)) return true;
|
|
1052
|
-
return Boolean(
|
|
1053
|
-
gh.collaborators.findBy("repo_id", repo.id).find((c) => c.user_id === user.id)
|
|
1054
|
-
);
|
|
1181
|
+
return Boolean(gh.collaborators.findBy("repo_id", repo.id).find((c) => c.user_id === user.id));
|
|
1055
1182
|
}
|
|
1056
1183
|
function assertRepoRead(gh, authUser, repo) {
|
|
1057
1184
|
if (canAccessRepo(gh, authUser, repo)) return;
|
|
@@ -1092,9 +1219,7 @@ function assertIssueWrite(gh, authUser, repo) {
|
|
|
1092
1219
|
|
|
1093
1220
|
// src/routes/users.ts
|
|
1094
1221
|
function listReposForUser(gh, user, type) {
|
|
1095
|
-
const owned = gh.repos.all().filter(
|
|
1096
|
-
(r) => r.owner_id === user.id && r.owner_type === "User"
|
|
1097
|
-
);
|
|
1222
|
+
const owned = gh.repos.all().filter((r) => r.owner_id === user.id && r.owner_type === "User");
|
|
1098
1223
|
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"));
|
|
1099
1224
|
if (type === "owner") return owned;
|
|
1100
1225
|
if (type === "member") return member;
|
|
@@ -1222,10 +1347,7 @@ function usersRoutes({ app, store, baseUrl }) {
|
|
|
1222
1347
|
});
|
|
1223
1348
|
app.get("/users", (c) => {
|
|
1224
1349
|
const since = Math.max(0, parseInt(c.req.query("since") ?? "0", 10) || 0);
|
|
1225
|
-
const perPage = Math.min(
|
|
1226
|
-
100,
|
|
1227
|
-
Math.max(1, parseInt(c.req.query("per_page") ?? "30", 10) || 30)
|
|
1228
|
-
);
|
|
1350
|
+
const perPage = Math.min(100, Math.max(1, parseInt(c.req.query("per_page") ?? "30", 10) || 30));
|
|
1229
1351
|
const ordered = gh.users.all().filter((u) => u.id > since).sort((a, b) => a.id - b.id);
|
|
1230
1352
|
const page = ordered.slice(0, perPage);
|
|
1231
1353
|
if (page.length === perPage && ordered.length > perPage) {
|
|
@@ -1813,7 +1935,7 @@ function reposRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
1813
1935
|
let ownerType = "User";
|
|
1814
1936
|
let ownerId = user.id;
|
|
1815
1937
|
let fullName = "";
|
|
1816
|
-
|
|
1938
|
+
const forkName = typeof body.name === "string" && body.name.trim() ? validateRepoName(body.name) : parent.name;
|
|
1817
1939
|
if (typeof body.organization === "string" && body.organization.trim()) {
|
|
1818
1940
|
const org = gh.orgs.findOneBy("login", body.organization.trim());
|
|
1819
1941
|
if (!org) throw notFound();
|
|
@@ -1896,9 +2018,7 @@ function reposRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
1896
2018
|
const u = gh.users.get(col.user_id);
|
|
1897
2019
|
if (!u) return null;
|
|
1898
2020
|
return { user: u, permission: col.permission };
|
|
1899
|
-
}).filter(
|
|
1900
|
-
(x) => Boolean(x)
|
|
1901
|
-
).sort((a, b) => a.user.login.localeCompare(b.user.login));
|
|
2021
|
+
}).filter((x) => Boolean(x)).sort((a, b) => a.user.login.localeCompare(b.user.login));
|
|
1902
2022
|
const { page, per_page } = parsePagination(c);
|
|
1903
2023
|
const total = users.length;
|
|
1904
2024
|
const start = (page - 1) * per_page;
|
|
@@ -2019,9 +2139,7 @@ function reposRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
2019
2139
|
const repo = lookupRepo(gh, owner, repoName);
|
|
2020
2140
|
if (!repo) throw notFound();
|
|
2021
2141
|
assertRepoRead(gh, c.get("authUser"), repo);
|
|
2022
|
-
const tags = [...gh.tags.findBy("repo_id", repo.id)].sort(
|
|
2023
|
-
(a, b) => a.tag.localeCompare(b.tag)
|
|
2024
|
-
);
|
|
2142
|
+
const tags = [...gh.tags.findBy("repo_id", repo.id)].sort((a, b) => a.tag.localeCompare(b.tag));
|
|
2025
2143
|
const { page, per_page } = parsePagination(c);
|
|
2026
2144
|
const total = tags.length;
|
|
2027
2145
|
const start = (page - 1) * per_page;
|
|
@@ -2931,9 +3049,7 @@ function checkMergeRequirements(gh, pr) {
|
|
|
2931
3049
|
if (checks && checks.contexts.length > 0) {
|
|
2932
3050
|
const runs = gh.checkRuns.findBy("repo_id", baseRepo.id).filter((r) => r.head_sha === pr.head_sha);
|
|
2933
3051
|
for (const ctx of checks.contexts) {
|
|
2934
|
-
const ok = runs.some(
|
|
2935
|
-
(r) => r.name === ctx && r.status === "completed" && r.conclusion === "success"
|
|
2936
|
-
);
|
|
3052
|
+
const ok = runs.some((r) => r.name === ctx && r.status === "completed" && r.conclusion === "success");
|
|
2937
3053
|
if (!ok) {
|
|
2938
3054
|
throw new ApiError(422, "Required status checks have not succeeded.");
|
|
2939
3055
|
}
|
|
@@ -3367,9 +3483,7 @@ ${commitMessage}` : commitTitle;
|
|
|
3367
3483
|
changes: 1,
|
|
3368
3484
|
blob_url: `${baseUrl}/${repo.full_name}/blob/${pr.head_sha}/${filename}`,
|
|
3369
3485
|
raw_url: `${baseUrl}/${repo.full_name}/raw/${pr.head_sha}/${filename}`,
|
|
3370
|
-
contents_url: `${baseUrl}/repos/${repo.full_name}/contents/${encodeURIComponent(
|
|
3371
|
-
filename
|
|
3372
|
-
)}?ref=${pr.head_ref}`,
|
|
3486
|
+
contents_url: `${baseUrl}/repos/${repo.full_name}/contents/${encodeURIComponent(filename)}?ref=${pr.head_ref}`,
|
|
3373
3487
|
patch: ""
|
|
3374
3488
|
}))
|
|
3375
3489
|
);
|
|
@@ -4106,7 +4220,7 @@ function reviewsRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
4106
4220
|
const pr = findPull3(gh, repo.id, pullNumber);
|
|
4107
4221
|
if (!pr) throw notFound();
|
|
4108
4222
|
const { page, per_page } = parsePagination(c);
|
|
4109
|
-
|
|
4223
|
+
const list = gh.reviews.findBy("repo_id", repo.id).filter((r) => r.pull_number === pullNumber);
|
|
4110
4224
|
list.sort((a, b) => a.id - b.id);
|
|
4111
4225
|
const total = list.length;
|
|
4112
4226
|
setLinkHeader(c, total, page, per_page);
|
|
@@ -4301,9 +4415,7 @@ function reviewsRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
4301
4415
|
if (!review) throw notFound();
|
|
4302
4416
|
const { page, per_page } = parsePagination(c);
|
|
4303
4417
|
const { sort, direction } = parseCommentSort2(c, "asc");
|
|
4304
|
-
let list = gh.comments.findBy("repo_id", repo.id).filter(
|
|
4305
|
-
(x) => x.comment_type === "review" && x.pull_number === pullNumber && x.review_id === reviewId
|
|
4306
|
-
);
|
|
4418
|
+
let list = gh.comments.findBy("repo_id", repo.id).filter((x) => x.comment_type === "review" && x.pull_number === pullNumber && x.review_id === reviewId);
|
|
4307
4419
|
list = sortComments2(list, sort, direction);
|
|
4308
4420
|
const total = list.length;
|
|
4309
4421
|
setLinkHeader(c, total, page, per_page);
|
|
@@ -4360,7 +4472,7 @@ function normalizeColor(raw) {
|
|
|
4360
4472
|
if (typeof raw !== "string" || !raw.trim()) {
|
|
4361
4473
|
throw new ApiError(422, "Validation failed");
|
|
4362
4474
|
}
|
|
4363
|
-
|
|
4475
|
+
const s = raw.trim().replace(/^#/, "");
|
|
4364
4476
|
if (!/^[0-9a-fA-F]{6}$/.test(s)) {
|
|
4365
4477
|
throw new ApiError(422, "Validation failed");
|
|
4366
4478
|
}
|
|
@@ -4446,7 +4558,7 @@ function labelsAndMilestonesRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
4446
4558
|
if (!repo) throw notFound();
|
|
4447
4559
|
assertRepoRead(gh, c.get("authUser"), repo);
|
|
4448
4560
|
const { page, per_page } = parsePagination(c);
|
|
4449
|
-
|
|
4561
|
+
const list = gh.labels.findBy("repo_id", repo.id).slice();
|
|
4450
4562
|
list.sort((a, b) => a.name.localeCompare(b.name));
|
|
4451
4563
|
const total = list.length;
|
|
4452
4564
|
setLinkHeader(c, total, page, per_page);
|
|
@@ -4806,7 +4918,7 @@ function labelsAndMilestonesRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
4806
4918
|
creator_id: actor.id
|
|
4807
4919
|
});
|
|
4808
4920
|
gh.milestones.update(row.id, { node_id: generateNodeId("Milestone", row.id) });
|
|
4809
|
-
|
|
4921
|
+
const m = recalcMilestoneIssueCounts(gh, repo.id, row.id);
|
|
4810
4922
|
const ownerLogin2 = ownerLoginOf(gh, repo);
|
|
4811
4923
|
webhooks.dispatch(
|
|
4812
4924
|
"milestone",
|
|
@@ -4963,7 +5075,7 @@ function labelsAndMilestonesRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
4963
5075
|
if (i.milestone_id !== ms.id) continue;
|
|
4964
5076
|
for (const lid of i.label_ids) labelIdSet.add(lid);
|
|
4965
5077
|
}
|
|
4966
|
-
|
|
5078
|
+
const labels = [...labelIdSet].map((id) => gh.labels.get(id)).filter(Boolean);
|
|
4967
5079
|
labels.sort((a, b) => a.name.localeCompare(b.name));
|
|
4968
5080
|
const total = labels.length;
|
|
4969
5081
|
setLinkHeader(c, total, page, per_page);
|
|
@@ -5446,9 +5558,7 @@ function branchesAndGitRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
5446
5558
|
const repo = lookupRepo(gh, owner, repoName);
|
|
5447
5559
|
if (!repo) throw notFound();
|
|
5448
5560
|
assertRepoRead(gh, c.get("authUser"), repo);
|
|
5449
|
-
let list = [...gh.branches.findBy("repo_id", repo.id)].sort(
|
|
5450
|
-
(a, b) => a.name.localeCompare(b.name)
|
|
5451
|
-
);
|
|
5561
|
+
let list = [...gh.branches.findBy("repo_id", repo.id)].sort((a, b) => a.name.localeCompare(b.name));
|
|
5452
5562
|
const prot = c.req.query("protected");
|
|
5453
5563
|
if (prot === "true") list = list.filter((b) => b.protected);
|
|
5454
5564
|
else if (prot === "false") list = list.filter((b) => !b.protected);
|
|
@@ -5851,12 +5961,7 @@ function branchesAndGitRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
5851
5961
|
object: {
|
|
5852
5962
|
type: tag.object_type,
|
|
5853
5963
|
sha: tag.object_sha,
|
|
5854
|
-
url: objectApiUrl(
|
|
5855
|
-
repo,
|
|
5856
|
-
baseUrl,
|
|
5857
|
-
resolveGitObjectType(gh, repo.id, tag.object_sha),
|
|
5858
|
-
tag.object_sha
|
|
5859
|
-
)
|
|
5964
|
+
url: objectApiUrl(repo, baseUrl, resolveGitObjectType(gh, repo.id, tag.object_sha), tag.object_sha)
|
|
5860
5965
|
},
|
|
5861
5966
|
verification: { verified: false, reason: "unsigned", signature: null, payload: null, verified_at: null }
|
|
5862
5967
|
});
|
|
@@ -5912,12 +6017,7 @@ function branchesAndGitRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
5912
6017
|
object: {
|
|
5913
6018
|
type: saved.object_type,
|
|
5914
6019
|
sha: saved.object_sha,
|
|
5915
|
-
url: objectApiUrl(
|
|
5916
|
-
repo,
|
|
5917
|
-
baseUrl,
|
|
5918
|
-
resolveGitObjectType(gh, repo.id, saved.object_sha),
|
|
5919
|
-
saved.object_sha
|
|
5920
|
-
)
|
|
6020
|
+
url: objectApiUrl(repo, baseUrl, resolveGitObjectType(gh, repo.id, saved.object_sha), saved.object_sha)
|
|
5921
6021
|
},
|
|
5922
6022
|
verification: { verified: false, reason: "unsigned", signature: null, payload: null, verified_at: null }
|
|
5923
6023
|
},
|
|
@@ -6068,10 +6168,7 @@ function orgsAndTeamsRoutes({ app, store, baseUrl }) {
|
|
|
6068
6168
|
const gh = getGitHubStore(store);
|
|
6069
6169
|
app.get("/organizations", (c) => {
|
|
6070
6170
|
const since = Math.max(0, parseInt(c.req.query("since") ?? "0", 10) || 0);
|
|
6071
|
-
const perPage = Math.min(
|
|
6072
|
-
100,
|
|
6073
|
-
Math.max(1, parseInt(c.req.query("per_page") ?? "30", 10) || 30)
|
|
6074
|
-
);
|
|
6171
|
+
const perPage = Math.min(100, Math.max(1, parseInt(c.req.query("per_page") ?? "30", 10) || 30));
|
|
6075
6172
|
const ordered = gh.orgs.all().filter((o) => o.id > since).sort((a, b) => a.id - b.id);
|
|
6076
6173
|
const page = ordered.slice(0, perPage);
|
|
6077
6174
|
if (page.length === perPage && ordered.length > perPage) {
|
|
@@ -6575,9 +6672,7 @@ _Auto-generated release notes (stub)._
|
|
|
6575
6672
|
const repo = lookupRepo(gh, owner, repoName);
|
|
6576
6673
|
if (!repo) throw notFound();
|
|
6577
6674
|
assertRepoRead(gh, c.get("authUser"), repo);
|
|
6578
|
-
const candidates = releasesForRepo(gh, repo.id).filter(
|
|
6579
|
-
(r) => !r.draft && !r.prerelease && r.published_at
|
|
6580
|
-
);
|
|
6675
|
+
const candidates = releasesForRepo(gh, repo.id).filter((r) => !r.draft && !r.prerelease && r.published_at);
|
|
6581
6676
|
if (candidates.length === 0) throw notFound();
|
|
6582
6677
|
candidates.sort((a, b) => {
|
|
6583
6678
|
const pa = a.published_at ?? a.created_at;
|
|
@@ -7792,9 +7887,7 @@ function searchRoutes({ app, store, baseUrl }) {
|
|
|
7792
7887
|
(a, b) => order === "desc" ? b.stargazers_count - a.stargazers_count : a.stargazers_count - b.stargazers_count
|
|
7793
7888
|
);
|
|
7794
7889
|
} else if (sortRaw === "forks") {
|
|
7795
|
-
list.sort(
|
|
7796
|
-
(a, b) => order === "desc" ? b.forks_count - a.forks_count : a.forks_count - b.forks_count
|
|
7797
|
-
);
|
|
7890
|
+
list.sort((a, b) => order === "desc" ? b.forks_count - a.forks_count : a.forks_count - b.forks_count);
|
|
7798
7891
|
} else if (sortRaw === "updated") {
|
|
7799
7892
|
list.sort(
|
|
7800
7893
|
(a, b) => order === "desc" ? b.updated_at.localeCompare(a.updated_at) : a.updated_at.localeCompare(b.updated_at)
|
|
@@ -7846,7 +7939,7 @@ function searchRoutes({ app, store, baseUrl }) {
|
|
|
7846
7939
|
if (body.toLowerCase().includes(t)) s += 1;
|
|
7847
7940
|
return s;
|
|
7848
7941
|
}
|
|
7849
|
-
|
|
7942
|
+
const sorted = [...hits];
|
|
7850
7943
|
if (sortRaw === "created") {
|
|
7851
7944
|
sorted.sort((a, b) => {
|
|
7852
7945
|
const ca = a.kind === "issue" ? a.issue.created_at : a.pr.created_at;
|
|
@@ -7921,7 +8014,7 @@ function searchRoutes({ app, store, baseUrl }) {
|
|
|
7921
8014
|
if (h.o.name?.toLowerCase().includes(text)) s += 1;
|
|
7922
8015
|
return s;
|
|
7923
8016
|
}
|
|
7924
|
-
|
|
8017
|
+
const list = [...hits];
|
|
7925
8018
|
if (sortRaw === "followers") {
|
|
7926
8019
|
list.sort((a, b) => {
|
|
7927
8020
|
const fa = a.kind === "user" ? a.u.followers : a.o.followers;
|
|
@@ -7947,9 +8040,7 @@ function searchRoutes({ app, store, baseUrl }) {
|
|
|
7947
8040
|
const total = list.length;
|
|
7948
8041
|
const slice = list.slice((page - 1) * per_page, (page - 1) * per_page + per_page);
|
|
7949
8042
|
setLinkHeader(c, total, page, per_page);
|
|
7950
|
-
const items = slice.map(
|
|
7951
|
-
(h) => h.kind === "user" ? formatUser(h.u, baseUrl) : formatOrgBrief(h.o, baseUrl)
|
|
7952
|
-
);
|
|
8043
|
+
const items = slice.map((h) => h.kind === "user" ? formatUser(h.u, baseUrl) : formatOrgBrief(h.o, baseUrl));
|
|
7953
8044
|
return c.json({
|
|
7954
8045
|
total_count: total,
|
|
7955
8046
|
incomplete_results: false,
|
|
@@ -8400,7 +8491,13 @@ function formatArtifact(a, repo, gh, baseUrl) {
|
|
|
8400
8491
|
digest: null,
|
|
8401
8492
|
created_at: a.created_at,
|
|
8402
8493
|
expires_at: a.expires_at,
|
|
8403
|
-
workflow_run: run ? {
|
|
8494
|
+
workflow_run: run ? {
|
|
8495
|
+
id: run.id,
|
|
8496
|
+
repository_id: repo.id,
|
|
8497
|
+
head_repository_id: repo.id,
|
|
8498
|
+
head_branch: run.head_branch,
|
|
8499
|
+
head_sha: run.head_sha
|
|
8500
|
+
} : null
|
|
8404
8501
|
};
|
|
8405
8502
|
}
|
|
8406
8503
|
function filterRuns(gh, runs, q) {
|
|
@@ -8518,7 +8615,11 @@ function actionsRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
8518
8615
|
void webhooks.dispatch(
|
|
8519
8616
|
"workflow_run",
|
|
8520
8617
|
"requested",
|
|
8521
|
-
{
|
|
8618
|
+
{
|
|
8619
|
+
workflow_run: formatWorkflowRun(created, repo, gh, baseUrl),
|
|
8620
|
+
repository: formatRepo(repo, gh, baseUrl),
|
|
8621
|
+
sender: formatUser(actor, baseUrl)
|
|
8622
|
+
},
|
|
8522
8623
|
ownerLogin2,
|
|
8523
8624
|
repo.name
|
|
8524
8625
|
);
|
|
@@ -8674,13 +8775,11 @@ function actionsRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
8674
8775
|
const runId = parseInt(c.req.param("run_id"), 10);
|
|
8675
8776
|
const run = gh.workflowRuns.get(runId);
|
|
8676
8777
|
if (!run || run.repo_id !== repo.id) throw notFound();
|
|
8677
|
-
return c.text(
|
|
8678
|
-
`2025-01-01T00:00:00.0000000Z Workflow run ${run.id} logs (stub)
|
|
8778
|
+
return c.text(`2025-01-01T00:00:00.0000000Z Workflow run ${run.id} logs (stub)
|
|
8679
8779
|
${run.head_sha}
|
|
8680
|
-
`,
|
|
8681
|
-
|
|
8682
|
-
|
|
8683
|
-
);
|
|
8780
|
+
`, 200, {
|
|
8781
|
+
"Content-Type": "text/plain; charset=utf-8"
|
|
8782
|
+
});
|
|
8684
8783
|
});
|
|
8685
8784
|
app.get("/repos/:owner/:repo/actions/runs/:run_id/jobs", (c) => {
|
|
8686
8785
|
const owner = c.req.param("owner");
|
|
@@ -9001,15 +9100,7 @@ function parseConclusion(raw) {
|
|
|
9001
9100
|
if (raw === void 0) return void 0;
|
|
9002
9101
|
if (raw === null) return null;
|
|
9003
9102
|
if (typeof raw !== "string") throw new ApiError(422, "Invalid conclusion");
|
|
9004
|
-
const allowed = /* @__PURE__ */ new Set([
|
|
9005
|
-
"success",
|
|
9006
|
-
"failure",
|
|
9007
|
-
"neutral",
|
|
9008
|
-
"cancelled",
|
|
9009
|
-
"skipped",
|
|
9010
|
-
"timed_out",
|
|
9011
|
-
"action_required"
|
|
9012
|
-
]);
|
|
9103
|
+
const allowed = /* @__PURE__ */ new Set(["success", "failure", "neutral", "cancelled", "skipped", "timed_out", "action_required"]);
|
|
9013
9104
|
if (!allowed.has(raw)) throw new ApiError(422, "Invalid conclusion");
|
|
9014
9105
|
return raw;
|
|
9015
9106
|
}
|
|
@@ -9393,7 +9484,7 @@ function checksRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
9393
9484
|
};
|
|
9394
9485
|
}
|
|
9395
9486
|
const nextStatus = patch.status ?? prev.status;
|
|
9396
|
-
|
|
9487
|
+
const nextConclusion = patch.conclusion !== void 0 ? patch.conclusion : prev.conclusion;
|
|
9397
9488
|
if (patch.head_sha && patch.head_sha !== prev.head_sha) {
|
|
9398
9489
|
const newSuite = getOrCreateCheckSuite(gh, repo, patch.head_sha, null);
|
|
9399
9490
|
patch.check_suite_id = newSuite.id;
|
|
@@ -9403,7 +9494,7 @@ function checksRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
9403
9494
|
throw new ApiError(422, "conclusion is required when status is completed");
|
|
9404
9495
|
}
|
|
9405
9496
|
patch.conclusion = nextConclusion;
|
|
9406
|
-
|
|
9497
|
+
const nextCompleted = patch.completed_at !== void 0 ? patch.completed_at : prev.completed_at;
|
|
9407
9498
|
if (!nextCompleted) {
|
|
9408
9499
|
patch.completed_at = timestamp();
|
|
9409
9500
|
}
|
|
@@ -9542,7 +9633,13 @@ function rateLimitRoutes({ app }) {
|
|
|
9542
9633
|
integration_manifest: { limit: 5e3, remaining: 4999, reset, used: 1, resource: "integration_manifest" },
|
|
9543
9634
|
source_import: { limit: 100, remaining: 99, reset, used: 1, resource: "source_import" },
|
|
9544
9635
|
code_scanning_upload: { limit: 500, remaining: 499, reset, used: 1, resource: "code_scanning_upload" },
|
|
9545
|
-
actions_runner_registration: {
|
|
9636
|
+
actions_runner_registration: {
|
|
9637
|
+
limit: 1e4,
|
|
9638
|
+
remaining: 9999,
|
|
9639
|
+
reset,
|
|
9640
|
+
used: 1,
|
|
9641
|
+
resource: "actions_runner_registration"
|
|
9642
|
+
},
|
|
9546
9643
|
scim: { limit: 15e3, remaining: 14999, reset, used: 1, resource: "scim" }
|
|
9547
9644
|
},
|
|
9548
9645
|
rate: rateLimit
|
|
@@ -9620,13 +9717,13 @@ function metaRoutes({ app, baseUrl }) {
|
|
|
9620
9717
|
"+1": `${baseUrl}/emojis/+1.png`,
|
|
9621
9718
|
"-1": `${baseUrl}/emojis/-1.png`,
|
|
9622
9719
|
"100": `${baseUrl}/emojis/100.png`,
|
|
9623
|
-
|
|
9624
|
-
|
|
9625
|
-
|
|
9626
|
-
|
|
9627
|
-
|
|
9628
|
-
|
|
9629
|
-
|
|
9720
|
+
tada: `${baseUrl}/emojis/tada.png`,
|
|
9721
|
+
rocket: `${baseUrl}/emojis/rocket.png`,
|
|
9722
|
+
heart: `${baseUrl}/emojis/heart.png`,
|
|
9723
|
+
eyes: `${baseUrl}/emojis/eyes.png`,
|
|
9724
|
+
thinking: `${baseUrl}/emojis/thinking.png`,
|
|
9725
|
+
thumbsup: `${baseUrl}/emojis/thumbsup.png`,
|
|
9726
|
+
thumbsdown: `${baseUrl}/emojis/thumbsdown.png`
|
|
9630
9727
|
});
|
|
9631
9728
|
});
|
|
9632
9729
|
app.get("/zen", (c) => {
|
|
@@ -9726,9 +9823,15 @@ function oauthRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
9726
9823
|
);
|
|
9727
9824
|
}
|
|
9728
9825
|
if (redirect_uri && !matchesRedirectUri(redirect_uri, oauthApp.redirect_uris)) {
|
|
9729
|
-
console.warn(
|
|
9826
|
+
console.warn(
|
|
9827
|
+
`[OAuth] redirect_uri mismatch: got "${redirect_uri}", registered: ${JSON.stringify(oauthApp.redirect_uris)}`
|
|
9828
|
+
);
|
|
9730
9829
|
return c.html(
|
|
9731
|
-
renderErrorPage(
|
|
9830
|
+
renderErrorPage(
|
|
9831
|
+
"Redirect URI mismatch",
|
|
9832
|
+
"The redirect_uri is not registered for this application.",
|
|
9833
|
+
SERVICE_LABEL
|
|
9834
|
+
),
|
|
9732
9835
|
400
|
|
9733
9836
|
);
|
|
9734
9837
|
}
|
|
@@ -9772,7 +9875,10 @@ function oauthRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
9772
9875
|
clientId: client_id,
|
|
9773
9876
|
created_at: Date.now()
|
|
9774
9877
|
});
|
|
9775
|
-
debug(
|
|
9878
|
+
debug(
|
|
9879
|
+
"github.oauth",
|
|
9880
|
+
`[OAuth callback] generated code: ${code.slice(0, 8)}... for login=${login}, pendingCodes size: ${getPendingCodes(store).size}`
|
|
9881
|
+
);
|
|
9776
9882
|
const sessionId = randomBytes2(24).toString("base64url");
|
|
9777
9883
|
getSessionMap(store).set(sessionId, login);
|
|
9778
9884
|
c.header("Set-Cookie", `_emu_session=${sessionId}; Path=/; HttpOnly; SameSite=Lax`);
|
|
@@ -9787,7 +9893,10 @@ function oauthRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
9787
9893
|
debug("github.oauth", `[OAuth token] Content-Type: ${contentType}`);
|
|
9788
9894
|
debug("github.oauth", `[OAuth token] Accept: ${accept}`);
|
|
9789
9895
|
debug("github.oauth", `[OAuth token] pendingCodes size: ${getPendingCodes(store).size}`);
|
|
9790
|
-
debug(
|
|
9896
|
+
debug(
|
|
9897
|
+
"github.oauth",
|
|
9898
|
+
`[OAuth token] pendingCodes keys: ${[...getPendingCodes(store).keys()].map((k) => k.slice(0, 8) + "...").join(", ")}`
|
|
9899
|
+
);
|
|
9791
9900
|
const rawText = await c.req.text();
|
|
9792
9901
|
debug("github.oauth", `[OAuth token] raw body: ${rawText.slice(0, 500)}`);
|
|
9793
9902
|
let raw;
|
|
@@ -9858,14 +9967,10 @@ function oauthRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
9858
9967
|
}
|
|
9859
9968
|
const oauthApp = gh.oauthApps.findOneBy("client_id", pending.clientId);
|
|
9860
9969
|
if (oauthApp) {
|
|
9861
|
-
const existingGrant = gh.oauthGrants.all().find(
|
|
9862
|
-
(g) => g.user_id === user.id && g.client_id === pending.clientId
|
|
9863
|
-
);
|
|
9970
|
+
const existingGrant = gh.oauthGrants.all().find((g) => g.user_id === user.id && g.client_id === pending.clientId);
|
|
9864
9971
|
const orgAccess = {};
|
|
9865
9972
|
for (const org of gh.orgs.all()) {
|
|
9866
|
-
const isMember = gh.teamMembers.all().some(
|
|
9867
|
-
(tm) => tm.user_id === user.id && gh.teams.get(tm.team_id)?.org_id === org.id
|
|
9868
|
-
);
|
|
9973
|
+
const isMember = gh.teamMembers.all().some((tm) => tm.user_id === user.id && gh.teams.get(tm.team_id)?.org_id === org.id);
|
|
9869
9974
|
if (isMember) orgAccess[org.login] = "granted";
|
|
9870
9975
|
}
|
|
9871
9976
|
if (existingGrant) {
|
|
@@ -9915,19 +10020,19 @@ function oauthRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
9915
10020
|
]);
|
|
9916
10021
|
});
|
|
9917
10022
|
const SCOPE_LABELS = {
|
|
9918
|
-
|
|
10023
|
+
repo: "Full control of private repositories",
|
|
9919
10024
|
"read:user": "Read all user profile data",
|
|
9920
10025
|
"user:email": "Access user email addresses (read-only)",
|
|
9921
|
-
|
|
9922
|
-
|
|
10026
|
+
user: "Full control of user profile",
|
|
10027
|
+
workflow: "Update GitHub action workflows",
|
|
9923
10028
|
"admin:org": "Full control of orgs and teams",
|
|
9924
10029
|
"admin:repo_hook": "Full control of repository hooks",
|
|
9925
10030
|
"read:org": "Read org and team membership",
|
|
9926
10031
|
"write:repo_hook": "Write repository hooks",
|
|
9927
10032
|
"read:repo_hook": "Read repository hooks",
|
|
9928
|
-
|
|
9929
|
-
|
|
9930
|
-
|
|
10033
|
+
delete_repo: "Delete repositories",
|
|
10034
|
+
gist: "Create gists",
|
|
10035
|
+
notifications: "Access notifications",
|
|
9931
10036
|
"write:packages": "Upload packages",
|
|
9932
10037
|
"read:packages": "Download packages",
|
|
9933
10038
|
"admin:gpg_key": "Full control of GPG keys",
|
|
@@ -9941,7 +10046,10 @@ function oauthRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
9941
10046
|
app.get("/settings/applications", (c) => {
|
|
9942
10047
|
const sessionUser = resolveSessionUser(c);
|
|
9943
10048
|
if (!sessionUser) {
|
|
9944
|
-
return c.html(
|
|
10049
|
+
return c.html(
|
|
10050
|
+
renderErrorPage("Unauthorized", "You must be authenticated to view this page.", SERVICE_LABEL),
|
|
10051
|
+
401
|
|
10052
|
+
);
|
|
9945
10053
|
}
|
|
9946
10054
|
const grants = gh.oauthGrants.findBy("user_id", sessionUser.id);
|
|
9947
10055
|
let bodyHtml;
|
|
@@ -9974,12 +10082,13 @@ function oauthRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
9974
10082
|
app.get("/settings/connections/applications/:client_id", (c) => {
|
|
9975
10083
|
const sessionUser = resolveSessionUser(c);
|
|
9976
10084
|
if (!sessionUser) {
|
|
9977
|
-
return c.html(
|
|
10085
|
+
return c.html(
|
|
10086
|
+
renderErrorPage("Unauthorized", "You must be authenticated to view this page.", SERVICE_LABEL),
|
|
10087
|
+
401
|
|
10088
|
+
);
|
|
9978
10089
|
}
|
|
9979
10090
|
const clientId = c.req.param("client_id");
|
|
9980
|
-
const grant = gh.oauthGrants.all().find(
|
|
9981
|
-
(g) => g.user_id === sessionUser.id && g.client_id === clientId
|
|
9982
|
-
);
|
|
10091
|
+
const grant = gh.oauthGrants.all().find((g) => g.user_id === sessionUser.id && g.client_id === clientId);
|
|
9983
10092
|
if (!grant) {
|
|
9984
10093
|
return c.html(renderErrorPage("Not Found", "No authorization found for this application.", SERVICE_LABEL), 404);
|
|
9985
10094
|
}
|
|
@@ -9991,9 +10100,7 @@ function oauthRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
9991
10100
|
month: "long",
|
|
9992
10101
|
day: "numeric"
|
|
9993
10102
|
});
|
|
9994
|
-
const permRows = grant.scopes.map(
|
|
9995
|
-
(s) => `<li><span class="check">✓</span> ${escapeHtml(scopeLabel(s))}</li>`
|
|
9996
|
-
).join("\n");
|
|
10103
|
+
const permRows = grant.scopes.map((s) => `<li><span class="check">✓</span> ${escapeHtml(scopeLabel(s))}</li>`).join("\n");
|
|
9997
10104
|
const orgRows = Object.entries(grant.org_access).map(([org, status]) => {
|
|
9998
10105
|
const letter = escapeHtml((org[0] ?? "?").toUpperCase());
|
|
9999
10106
|
const badgeClass = status === "granted" ? "badge-granted" : status === "denied" ? "badge-denied" : "badge-requested";
|
|
@@ -10037,12 +10144,13 @@ function oauthRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
10037
10144
|
app.post("/settings/connections/applications/:client_id/revoke", (c) => {
|
|
10038
10145
|
const sessionUser = resolveSessionUser(c);
|
|
10039
10146
|
if (!sessionUser) {
|
|
10040
|
-
return c.html(
|
|
10147
|
+
return c.html(
|
|
10148
|
+
renderErrorPage("Unauthorized", "You must be authenticated to perform this action.", SERVICE_LABEL),
|
|
10149
|
+
401
|
|
10150
|
+
);
|
|
10041
10151
|
}
|
|
10042
10152
|
const clientId = c.req.param("client_id");
|
|
10043
|
-
const grant = gh.oauthGrants.all().find(
|
|
10044
|
-
(g) => g.user_id === sessionUser.id && g.client_id === clientId
|
|
10045
|
-
);
|
|
10153
|
+
const grant = gh.oauthGrants.all().find((g) => g.user_id === sessionUser.id && g.client_id === clientId);
|
|
10046
10154
|
if (grant) {
|
|
10047
10155
|
gh.oauthGrants.delete(grant.id);
|
|
10048
10156
|
}
|
|
@@ -10073,10 +10181,13 @@ function appsRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
10073
10181
|
app.get("/app", (c) => {
|
|
10074
10182
|
const authApp = requireApp(c);
|
|
10075
10183
|
if (!authApp) {
|
|
10076
|
-
return c.json(
|
|
10077
|
-
|
|
10078
|
-
|
|
10079
|
-
|
|
10184
|
+
return c.json(
|
|
10185
|
+
{
|
|
10186
|
+
message: "A JSON web token could not be decoded",
|
|
10187
|
+
documentation_url: "https://docs.github.com/rest"
|
|
10188
|
+
},
|
|
10189
|
+
401
|
|
10190
|
+
);
|
|
10080
10191
|
}
|
|
10081
10192
|
const ghApp = gh.apps.all().find((a) => a.app_id === authApp.appId);
|
|
10082
10193
|
if (!ghApp) {
|
|
@@ -10102,29 +10213,31 @@ function appsRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
10102
10213
|
app.get("/app/installations", (c) => {
|
|
10103
10214
|
const authApp = requireApp(c);
|
|
10104
10215
|
if (!authApp) {
|
|
10105
|
-
return c.json(
|
|
10106
|
-
|
|
10107
|
-
|
|
10108
|
-
|
|
10216
|
+
return c.json(
|
|
10217
|
+
{
|
|
10218
|
+
message: "A JSON web token could not be decoded",
|
|
10219
|
+
documentation_url: "https://docs.github.com/rest"
|
|
10220
|
+
},
|
|
10221
|
+
401
|
|
10222
|
+
);
|
|
10109
10223
|
}
|
|
10110
10224
|
const installations = gh.appInstallations.findBy("app_id", authApp.appId);
|
|
10111
10225
|
const ghApp = gh.apps.all().find((a) => a.app_id === authApp.appId);
|
|
10112
|
-
return c.json(
|
|
10113
|
-
installations.map((inst) => formatInstallation(inst, ghApp, baseUrl))
|
|
10114
|
-
);
|
|
10226
|
+
return c.json(installations.map((inst) => formatInstallation(inst, ghApp, baseUrl)));
|
|
10115
10227
|
});
|
|
10116
10228
|
app.get("/app/installations/:installation_id", (c) => {
|
|
10117
10229
|
const authApp = requireApp(c);
|
|
10118
10230
|
if (!authApp) {
|
|
10119
|
-
return c.json(
|
|
10120
|
-
|
|
10121
|
-
|
|
10122
|
-
|
|
10231
|
+
return c.json(
|
|
10232
|
+
{
|
|
10233
|
+
message: "A JSON web token could not be decoded",
|
|
10234
|
+
documentation_url: "https://docs.github.com/rest"
|
|
10235
|
+
},
|
|
10236
|
+
401
|
|
10237
|
+
);
|
|
10123
10238
|
}
|
|
10124
10239
|
const installationId = parseInt(c.req.param("installation_id"), 10);
|
|
10125
|
-
const inst = gh.appInstallations.all().find(
|
|
10126
|
-
(i) => i.installation_id === installationId && i.app_id === authApp.appId
|
|
10127
|
-
);
|
|
10240
|
+
const inst = gh.appInstallations.all().find((i) => i.installation_id === installationId && i.app_id === authApp.appId);
|
|
10128
10241
|
if (!inst) {
|
|
10129
10242
|
return c.json({ message: "Not Found", documentation_url: "https://docs.github.com/rest" }, 404);
|
|
10130
10243
|
}
|
|
@@ -10134,15 +10247,16 @@ function appsRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
10134
10247
|
app.post("/app/installations/:installation_id/access_tokens", async (c) => {
|
|
10135
10248
|
const authApp = requireApp(c);
|
|
10136
10249
|
if (!authApp) {
|
|
10137
|
-
return c.json(
|
|
10138
|
-
|
|
10139
|
-
|
|
10140
|
-
|
|
10250
|
+
return c.json(
|
|
10251
|
+
{
|
|
10252
|
+
message: "A JSON web token could not be decoded",
|
|
10253
|
+
documentation_url: "https://docs.github.com/rest"
|
|
10254
|
+
},
|
|
10255
|
+
401
|
|
10256
|
+
);
|
|
10141
10257
|
}
|
|
10142
10258
|
const installationId = parseInt(c.req.param("installation_id"), 10);
|
|
10143
|
-
const inst = gh.appInstallations.all().find(
|
|
10144
|
-
(i) => i.installation_id === installationId && i.app_id === authApp.appId
|
|
10145
|
-
);
|
|
10259
|
+
const inst = gh.appInstallations.all().find((i) => i.installation_id === installationId && i.app_id === authApp.appId);
|
|
10146
10260
|
if (!inst) {
|
|
10147
10261
|
return c.json({ message: "Not Found", documentation_url: "https://docs.github.com/rest" }, 404);
|
|
10148
10262
|
}
|
|
@@ -10176,13 +10290,16 @@ function appsRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
10176
10290
|
full_name: r.full_name,
|
|
10177
10291
|
private: r.private
|
|
10178
10292
|
}));
|
|
10179
|
-
return c.json(
|
|
10180
|
-
|
|
10181
|
-
|
|
10182
|
-
|
|
10183
|
-
|
|
10184
|
-
|
|
10185
|
-
|
|
10293
|
+
return c.json(
|
|
10294
|
+
{
|
|
10295
|
+
token,
|
|
10296
|
+
expires_at: expiresAt,
|
|
10297
|
+
permissions: requestedPermissions,
|
|
10298
|
+
repository_selection: inst.repository_selection,
|
|
10299
|
+
...inst.repository_selection === "selected" ? { repositories: repos } : {}
|
|
10300
|
+
},
|
|
10301
|
+
201
|
|
10302
|
+
);
|
|
10186
10303
|
});
|
|
10187
10304
|
app.get("/repos/:owner/:repo/installation", (c) => {
|
|
10188
10305
|
const owner = c.req.param("owner");
|
|
@@ -10211,9 +10328,7 @@ function appsRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
10211
10328
|
if (!org) {
|
|
10212
10329
|
return c.json({ message: "Not Found", documentation_url: "https://docs.github.com/rest" }, 404);
|
|
10213
10330
|
}
|
|
10214
|
-
const inst = gh.appInstallations.all().find(
|
|
10215
|
-
(i) => i.account_id === org.id && i.account_type === "Organization"
|
|
10216
|
-
);
|
|
10331
|
+
const inst = gh.appInstallations.all().find((i) => i.account_id === org.id && i.account_type === "Organization");
|
|
10217
10332
|
if (!inst) {
|
|
10218
10333
|
return c.json({ message: "Not Found", documentation_url: "https://docs.github.com/rest" }, 404);
|
|
10219
10334
|
}
|
|
@@ -10226,9 +10341,7 @@ function appsRoutes({ app, store, baseUrl, tokenMap }) {
|
|
|
10226
10341
|
if (!user) {
|
|
10227
10342
|
return c.json({ message: "Not Found", documentation_url: "https://docs.github.com/rest" }, 404);
|
|
10228
10343
|
}
|
|
10229
|
-
const inst = gh.appInstallations.all().find(
|
|
10230
|
-
(i) => i.account_id === user.id && i.account_type === "User"
|
|
10231
|
-
);
|
|
10344
|
+
const inst = gh.appInstallations.all().find((i) => i.account_id === user.id && i.account_type === "User");
|
|
10232
10345
|
if (!inst) {
|
|
10233
10346
|
return c.json({ message: "Not Found", documentation_url: "https://docs.github.com/rest" }, 404);
|
|
10234
10347
|
}
|