emulate 0.4.1 → 0.5.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 +59 -10
- package/dist/api.d.ts +2 -1
- package/dist/api.js +232 -96
- package/dist/api.js.map +1 -1
- package/dist/{chunk-TEPNEZ63.js → chunk-AQ2CLRU3.js} +26 -23
- package/dist/chunk-AQ2CLRU3.js.map +1 -0
- package/dist/chunk-WVQMFHQM.js +83 -0
- package/dist/chunk-WVQMFHQM.js.map +1 -0
- package/dist/{dist-RDFBZ5O6.js → dist-4X2KPMAJ.js} +212 -47
- package/dist/dist-4X2KPMAJ.js.map +1 -0
- package/dist/{dist-OTJZRQ3Q.js → dist-5JVGPOL3.js} +217 -75
- package/dist/dist-5JVGPOL3.js.map +1 -0
- package/dist/{dist-G7WQPZ3Y.js → dist-CE6BUCWQ.js} +211 -60
- package/dist/dist-CE6BUCWQ.js.map +1 -0
- package/dist/{dist-6JFNJPUU.js → dist-CFST4X4K.js} +172 -22
- package/dist/dist-CFST4X4K.js.map +1 -0
- package/dist/{dist-YOVM5HEY.js → dist-ENKE2S7V.js} +521 -60
- package/dist/dist-ENKE2S7V.js.map +1 -0
- package/dist/{dist-RMK3BS5M.js → dist-ETHHYBGF.js} +197 -33
- package/dist/dist-ETHHYBGF.js.map +1 -0
- package/dist/{dist-QMOJM6DV.js → dist-IBXD3O6A.js} +239 -54
- package/dist/dist-IBXD3O6A.js.map +1 -0
- package/dist/dist-J6LHUR52.js +1899 -0
- package/dist/dist-J6LHUR52.js.map +1 -0
- package/dist/{dist-6EW7SSOZ.js → dist-KKTYBE5S.js} +391 -222
- package/dist/dist-KKTYBE5S.js.map +1 -0
- package/dist/{dist-VVXVP5EZ.js → dist-LDUHEJAN.js} +553 -91
- package/dist/dist-LDUHEJAN.js.map +1 -0
- package/dist/{dist-B674PYKV.js → dist-PWGOAQC6.js} +22 -43
- package/dist/dist-PWGOAQC6.js.map +1 -0
- package/dist/{dist-H6JYGQM4.js → dist-REDHDZ3V.js} +272 -157
- package/dist/dist-REDHDZ3V.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 +365 -108
- package/dist/index.js.map +1 -1
- package/package.json +17 -14
- 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.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,4 +1,4 @@
|
|
|
1
|
-
import "./chunk-
|
|
1
|
+
import "./chunk-AQ2CLRU3.js";
|
|
2
2
|
|
|
3
3
|
// ../@emulators/vercel/dist/index.js
|
|
4
4
|
import { randomBytes } from "crypto";
|
|
@@ -15,7 +15,10 @@ function getVercelStore(store) {
|
|
|
15
15
|
teamMembers: store.collection("vercel.team_members", ["teamId", "userId"]),
|
|
16
16
|
projects: store.collection("vercel.projects", ["uid", "name", "accountId"]),
|
|
17
17
|
deployments: store.collection("vercel.deployments", ["uid", "projectId", "url"]),
|
|
18
|
-
deploymentAliases: store.collection("vercel.deployment_aliases", [
|
|
18
|
+
deploymentAliases: store.collection("vercel.deployment_aliases", [
|
|
19
|
+
"deploymentId",
|
|
20
|
+
"projectId"
|
|
21
|
+
]),
|
|
19
22
|
builds: store.collection("vercel.builds", ["deploymentId"]),
|
|
20
23
|
deploymentEvents: store.collection("vercel.deployment_events", ["deploymentId"]),
|
|
21
24
|
files: store.collection("vercel.files", ["digest"]),
|
|
@@ -57,7 +60,7 @@ function resolveTeamScope(c, vs) {
|
|
|
57
60
|
return { accountId: user.uid, team: null };
|
|
58
61
|
}
|
|
59
62
|
function lookupProject(vs, idOrName, accountId) {
|
|
60
|
-
|
|
63
|
+
const project = vs.projects.findOneBy("uid", idOrName);
|
|
61
64
|
if (project && project.accountId === accountId) return project;
|
|
62
65
|
const byName = vs.projects.findBy("name", idOrName);
|
|
63
66
|
return byName.find((p) => p.accountId === accountId);
|
|
@@ -285,6 +288,7 @@ var FONTS = {
|
|
|
285
288
|
"geist-sans.woff2": readFileSync(join(__dirname, "fonts", "geist-sans.woff2")),
|
|
286
289
|
"GeistPixel-Square.woff2": readFileSync(join(__dirname, "fonts", "GeistPixel-Square.woff2"))
|
|
287
290
|
};
|
|
291
|
+
var FAVICON = readFileSync(join(__dirname, "fonts", "favicon.ico"));
|
|
288
292
|
function escapeHtml(s) {
|
|
289
293
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
290
294
|
}
|
|
@@ -436,6 +440,132 @@ body{
|
|
|
436
440
|
.app-link-name{font-weight:600;font-size:.875rem;color:#33ff00;}
|
|
437
441
|
.app-link-scopes{font-size:.6875rem;color:#1a8c00;margin-top:1px;}
|
|
438
442
|
.empty{color:#1a8c00;text-align:center;padding:28px 0;font-size:.875rem;}
|
|
443
|
+
|
|
444
|
+
.inspector-layout{max-width:960px;margin:0 auto;padding:28px 20px;}
|
|
445
|
+
.inspector-tabs{display:flex;gap:4px;margin-bottom:20px;}
|
|
446
|
+
.inspector-tabs a{
|
|
447
|
+
padding:7px 16px;border-radius:6px;text-decoration:none;
|
|
448
|
+
font-size:.8125rem;color:#1a8c00;border:1px solid transparent;
|
|
449
|
+
transition:color .15s,border-color .15s;
|
|
450
|
+
}
|
|
451
|
+
.inspector-tabs a:hover{color:#33ff00;}
|
|
452
|
+
.inspector-tabs a.active{color:#33ff00;font-weight:600;border-color:#0a3300;background:#0a3300;}
|
|
453
|
+
.inspector-section{margin-bottom:24px;}
|
|
454
|
+
.inspector-section h2{
|
|
455
|
+
font-family:'Geist Pixel',monospace;
|
|
456
|
+
font-size:1rem;font-weight:600;color:#33ff00;margin-bottom:10px;
|
|
457
|
+
}
|
|
458
|
+
.inspector-section h3{
|
|
459
|
+
font-family:'Geist Pixel',monospace;
|
|
460
|
+
font-size:.875rem;font-weight:600;color:#1a8c00;margin:16px 0 8px;
|
|
461
|
+
}
|
|
462
|
+
.inspector-table{width:100%;border-collapse:collapse;margin-bottom:12px;}
|
|
463
|
+
.inspector-table th,.inspector-table td{
|
|
464
|
+
text-align:left;padding:8px 12px;border-bottom:1px solid #0a3300;
|
|
465
|
+
font-size:.8125rem;
|
|
466
|
+
}
|
|
467
|
+
.inspector-table th{color:#1a8c00;font-weight:600;font-size:.75rem;text-transform:uppercase;letter-spacing:.04em;}
|
|
468
|
+
.inspector-table td{color:#33ff00;}
|
|
469
|
+
.inspector-table tbody tr{transition:background .1s;}
|
|
470
|
+
.inspector-table tbody tr:hover{background:#0a3300;}
|
|
471
|
+
.inspector-empty{color:#1a8c00;text-align:center;padding:20px 0;font-size:.8125rem;}
|
|
472
|
+
|
|
473
|
+
.checkout-layout{
|
|
474
|
+
display:flex;min-height:calc(100vh - 42px);
|
|
475
|
+
}
|
|
476
|
+
.checkout-summary{
|
|
477
|
+
flex:1;background:#020;padding:48px 40px 48px 10%;
|
|
478
|
+
display:flex;flex-direction:column;justify-content:center;
|
|
479
|
+
border-right:1px solid #0a3300;
|
|
480
|
+
}
|
|
481
|
+
.checkout-form-side{
|
|
482
|
+
flex:1;background:#000;padding:48px 10% 48px 40px;
|
|
483
|
+
display:flex;flex-direction:column;justify-content:center;
|
|
484
|
+
}
|
|
485
|
+
.checkout-merchant{
|
|
486
|
+
display:flex;align-items:center;gap:10px;margin-bottom:6px;
|
|
487
|
+
}
|
|
488
|
+
.checkout-merchant-name{
|
|
489
|
+
font-family:'Geist Pixel',monospace;
|
|
490
|
+
font-size:.9375rem;font-weight:600;color:#33ff00;
|
|
491
|
+
}
|
|
492
|
+
.checkout-test-badge{
|
|
493
|
+
font-size:.625rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
|
|
494
|
+
background:#0a3300;color:#1a8c00;padding:2px 8px;border-radius:4px;
|
|
495
|
+
}
|
|
496
|
+
.checkout-total{
|
|
497
|
+
font-family:'Geist Pixel',monospace;
|
|
498
|
+
font-size:2rem;font-weight:700;color:#33ff00;margin:8px 0 28px;
|
|
499
|
+
}
|
|
500
|
+
.checkout-line-item{
|
|
501
|
+
display:flex;align-items:center;gap:14px;padding:14px 0;
|
|
502
|
+
border-bottom:1px solid #0a3300;
|
|
503
|
+
}
|
|
504
|
+
.checkout-line-item:first-child{border-top:1px solid #0a3300;}
|
|
505
|
+
.checkout-item-icon{
|
|
506
|
+
width:42px;height:42px;border-radius:6px;background:#0a3300;
|
|
507
|
+
display:flex;align-items:center;justify-content:center;flex-shrink:0;
|
|
508
|
+
font-family:'Geist Pixel',monospace;font-size:.875rem;font-weight:700;color:#116600;
|
|
509
|
+
}
|
|
510
|
+
.checkout-item-details{flex:1;min-width:0;}
|
|
511
|
+
.checkout-item-name{font-size:.875rem;font-weight:600;color:#33ff00;}
|
|
512
|
+
.checkout-item-qty{font-size:.75rem;color:#1a8c00;margin-top:2px;}
|
|
513
|
+
.checkout-item-price{
|
|
514
|
+
font-size:.875rem;font-weight:600;color:#33ff00;text-align:right;white-space:nowrap;
|
|
515
|
+
}
|
|
516
|
+
.checkout-item-unit{font-size:.6875rem;color:#1a8c00;text-align:right;margin-top:2px;}
|
|
517
|
+
.checkout-totals{margin-top:20px;}
|
|
518
|
+
.checkout-totals-row{
|
|
519
|
+
display:flex;justify-content:space-between;padding:6px 0;
|
|
520
|
+
font-size:.8125rem;color:#1a8c00;
|
|
521
|
+
}
|
|
522
|
+
.checkout-totals-row.total{
|
|
523
|
+
border-top:1px solid #0a3300;margin-top:8px;padding-top:14px;
|
|
524
|
+
font-size:.9375rem;font-weight:600;color:#33ff00;
|
|
525
|
+
}
|
|
526
|
+
.checkout-form-section{margin-bottom:24px;}
|
|
527
|
+
.checkout-form-label{
|
|
528
|
+
font-size:.8125rem;font-weight:600;color:#33ff00;margin-bottom:8px;display:block;
|
|
529
|
+
}
|
|
530
|
+
.checkout-input{
|
|
531
|
+
width:100%;padding:10px 12px;border:1px solid #0a3300;border-radius:6px;
|
|
532
|
+
background:#020;color:#33ff00;font:inherit;font-size:.875rem;
|
|
533
|
+
transition:border-color .15s;outline:none;
|
|
534
|
+
}
|
|
535
|
+
.checkout-input:focus{border-color:#33ff00;}
|
|
536
|
+
.checkout-input::placeholder{color:#116600;}
|
|
537
|
+
.checkout-card-box{
|
|
538
|
+
border:1px solid #0a3300;border-radius:6px;padding:14px;
|
|
539
|
+
background:#020;
|
|
540
|
+
}
|
|
541
|
+
.checkout-card-row{
|
|
542
|
+
display:flex;gap:12px;margin-top:10px;
|
|
543
|
+
}
|
|
544
|
+
.checkout-card-row .checkout-input{flex:1;}
|
|
545
|
+
.checkout-sim-note{
|
|
546
|
+
font-size:.6875rem;color:#1a8c00;margin-top:10px;text-align:center;
|
|
547
|
+
font-style:italic;
|
|
548
|
+
}
|
|
549
|
+
.checkout-pay-btn{
|
|
550
|
+
width:100%;padding:14px;border:none;border-radius:8px;
|
|
551
|
+
background:#33ff00;color:#000;font:inherit;font-size:.9375rem;font-weight:700;
|
|
552
|
+
cursor:pointer;transition:background .15s;
|
|
553
|
+
font-family:'Geist Pixel',monospace;
|
|
554
|
+
}
|
|
555
|
+
.checkout-pay-btn:hover{background:#44ff22;}
|
|
556
|
+
.checkout-cancel{
|
|
557
|
+
text-align:center;margin-top:14px;
|
|
558
|
+
}
|
|
559
|
+
.checkout-cancel a{
|
|
560
|
+
color:#1a8c00;text-decoration:none;font-size:.8125rem;
|
|
561
|
+
transition:color .15s;
|
|
562
|
+
}
|
|
563
|
+
.checkout-cancel a:hover{color:#33ff00;}
|
|
564
|
+
@media(max-width:768px){
|
|
565
|
+
.checkout-layout{flex-direction:column;}
|
|
566
|
+
.checkout-summary{padding:32px 20px;border-right:none;border-bottom:1px solid #0a3300;}
|
|
567
|
+
.checkout-form-side{padding:32px 20px;}
|
|
568
|
+
}
|
|
439
569
|
`;
|
|
440
570
|
var POWERED_BY = `<div class="powered-by">Powered by <a href="https://emulate.dev" target="_blank" rel="noopener">emulate</a></div>`;
|
|
441
571
|
function emuBar(service) {
|
|
@@ -455,6 +585,7 @@ function head(title) {
|
|
|
455
585
|
<head>
|
|
456
586
|
<meta charset="utf-8"/>
|
|
457
587
|
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
|
588
|
+
<link rel="icon" href="/_emulate/favicon.ico"/>
|
|
458
589
|
<title>${escapeHtml(title)} | emulate</title>
|
|
459
590
|
<style>${CSS}</style>
|
|
460
591
|
</head>`;
|
|
@@ -932,7 +1063,9 @@ function projectsRoutes({ app, store, baseUrl }) {
|
|
|
932
1063
|
key,
|
|
933
1064
|
value: typeof ev.value === "string" ? ev.value : String(ev.value ?? ""),
|
|
934
1065
|
type: ev.type === "system" || ev.type === "encrypted" || ev.type === "plain" || ev.type === "secret" || ev.type === "sensitive" ? ev.type : "encrypted",
|
|
935
|
-
target: Array.isArray(ev.target) ? ev.target.filter(
|
|
1066
|
+
target: Array.isArray(ev.target) ? ev.target.filter(
|
|
1067
|
+
(t) => t === "production" || t === "preview" || t === "development"
|
|
1068
|
+
) : ["production", "preview", "development"],
|
|
936
1069
|
gitBranch: typeof ev.gitBranch === "string" ? ev.gitBranch : null,
|
|
937
1070
|
customEnvironmentIds: Array.isArray(ev.customEnvironmentIds) ? ev.customEnvironmentIds : [],
|
|
938
1071
|
comment: typeof ev.comment === "string" ? ev.comment : null,
|
|
@@ -1915,11 +2048,17 @@ function parseEnvRow(body) {
|
|
|
1915
2048
|
}
|
|
1916
2049
|
const type = parseType(body.type);
|
|
1917
2050
|
if (type === "invalid") {
|
|
1918
|
-
return {
|
|
2051
|
+
return {
|
|
2052
|
+
row: {},
|
|
2053
|
+
error: "Invalid value: type must be one of system, encrypted, plain, secret, sensitive"
|
|
2054
|
+
};
|
|
1919
2055
|
}
|
|
1920
2056
|
const target = parseTarget(body.target);
|
|
1921
2057
|
if (target === "invalid") {
|
|
1922
|
-
return {
|
|
2058
|
+
return {
|
|
2059
|
+
row: {},
|
|
2060
|
+
error: "Invalid value: target must be a non-empty array of production, preview, development"
|
|
2061
|
+
};
|
|
1923
2062
|
}
|
|
1924
2063
|
const customEnvironmentIds = parseCustomEnvironmentIds(body.customEnvironmentIds);
|
|
1925
2064
|
if (customEnvironmentIds === "invalid") {
|
|
@@ -2027,9 +2166,7 @@ function envRoutes({ app, store }) {
|
|
|
2027
2166
|
}
|
|
2028
2167
|
const { row } = parsed;
|
|
2029
2168
|
const existingDb = findEnvByKeyAndTargetsOverlap(vs, project.uid, row.key, row.target);
|
|
2030
|
-
const existingPending = pending.find(
|
|
2031
|
-
(e) => e.key === row.key && targetsOverlap(e.target, row.target)
|
|
2032
|
-
);
|
|
2169
|
+
const existingPending = pending.find((e) => e.key === row.key && targetsOverlap(e.target, row.target));
|
|
2033
2170
|
if (upsert) {
|
|
2034
2171
|
const toUpdate = existingDb ?? existingPending;
|
|
2035
2172
|
if (toUpdate) {
|
|
@@ -2128,14 +2265,24 @@ function envRoutes({ app, store }) {
|
|
|
2128
2265
|
if ("type" in body) {
|
|
2129
2266
|
const t = parseType(body.type);
|
|
2130
2267
|
if (t === "invalid") {
|
|
2131
|
-
return vercelErr5(
|
|
2268
|
+
return vercelErr5(
|
|
2269
|
+
c,
|
|
2270
|
+
400,
|
|
2271
|
+
"bad_request",
|
|
2272
|
+
"Invalid value: type must be one of system, encrypted, plain, secret, sensitive"
|
|
2273
|
+
);
|
|
2132
2274
|
}
|
|
2133
2275
|
patch.type = t;
|
|
2134
2276
|
}
|
|
2135
2277
|
if ("target" in body) {
|
|
2136
2278
|
const t = parseTarget(body.target);
|
|
2137
2279
|
if (t === "invalid") {
|
|
2138
|
-
return vercelErr5(
|
|
2280
|
+
return vercelErr5(
|
|
2281
|
+
c,
|
|
2282
|
+
400,
|
|
2283
|
+
"bad_request",
|
|
2284
|
+
"Invalid value: target must be a non-empty array of production, preview, development"
|
|
2285
|
+
);
|
|
2139
2286
|
}
|
|
2140
2287
|
patch.target = t;
|
|
2141
2288
|
}
|
|
@@ -2230,11 +2377,23 @@ function oauthRoutes({ app, store, tokenMap }) {
|
|
|
2230
2377
|
if (integrationsConfigured) {
|
|
2231
2378
|
const integration = vs.integrations.findOneBy("client_id", client_id);
|
|
2232
2379
|
if (!integration) {
|
|
2233
|
-
return c.html(
|
|
2380
|
+
return c.html(
|
|
2381
|
+
renderErrorPage("Application not found", `The client_id '${client_id}' is not registered.`, SERVICE_LABEL),
|
|
2382
|
+
400
|
|
2383
|
+
);
|
|
2234
2384
|
}
|
|
2235
2385
|
if (redirect_uri && !matchesRedirectUri(redirect_uri, integration.redirect_uris)) {
|
|
2236
|
-
console.warn(
|
|
2237
|
-
|
|
2386
|
+
console.warn(
|
|
2387
|
+
`[OAuth] redirect_uri mismatch: got "${redirect_uri}", registered: ${JSON.stringify(integration.redirect_uris)}`
|
|
2388
|
+
);
|
|
2389
|
+
return c.html(
|
|
2390
|
+
renderErrorPage(
|
|
2391
|
+
"Redirect URI mismatch",
|
|
2392
|
+
"The redirect_uri is not registered for this application.",
|
|
2393
|
+
SERVICE_LABEL
|
|
2394
|
+
),
|
|
2395
|
+
400
|
|
2396
|
+
);
|
|
2238
2397
|
}
|
|
2239
2398
|
integrationName = integration.name;
|
|
2240
2399
|
}
|
|
@@ -2282,7 +2441,10 @@ function oauthRoutes({ app, store, tokenMap }) {
|
|
|
2282
2441
|
codeChallengeMethod: code_challenge_method || null,
|
|
2283
2442
|
created_at: Date.now()
|
|
2284
2443
|
});
|
|
2285
|
-
debug(
|
|
2444
|
+
debug(
|
|
2445
|
+
"vercel.oauth",
|
|
2446
|
+
`[Vercel callback] generated code: ${code.slice(0, 8)}... for username=${username}, challenge=${code_challenge ? "present" : "none"}, pendingCodes size: ${pendingCodes.size}`
|
|
2447
|
+
);
|
|
2286
2448
|
const url = new URL(redirect_uri);
|
|
2287
2449
|
url.searchParams.set("code", code);
|
|
2288
2450
|
if (state !== "") url.searchParams.set("state", state);
|
|
@@ -2294,7 +2456,10 @@ function oauthRoutes({ app, store, tokenMap }) {
|
|
|
2294
2456
|
const pendingCodes = getPendingCodes(store);
|
|
2295
2457
|
debug("vercel.oauth", `[Vercel token] Content-Type: ${contentType}`);
|
|
2296
2458
|
debug("vercel.oauth", `[Vercel token] pendingCodes size: ${pendingCodes.size}`);
|
|
2297
|
-
debug(
|
|
2459
|
+
debug(
|
|
2460
|
+
"vercel.oauth",
|
|
2461
|
+
`[Vercel token] pendingCodes keys: ${[...pendingCodes.keys()].map((k) => k.slice(0, 8) + "...").join(", ")}`
|
|
2462
|
+
);
|
|
2298
2463
|
const rawText = await c.req.text();
|
|
2299
2464
|
debug("vercel.oauth", `[Vercel token] raw body: ${rawText.slice(0, 500)}`);
|
|
2300
2465
|
let body;
|
|
@@ -2316,73 +2481,70 @@ function oauthRoutes({ app, store, tokenMap }) {
|
|
|
2316
2481
|
debug("vercel.oauth", `[Vercel token] code: ${code.slice(0, 8)}... (len=${code.length})`);
|
|
2317
2482
|
debug("vercel.oauth", `[Vercel token] client_id: ${bodyClientId}`);
|
|
2318
2483
|
debug("vercel.oauth", `[Vercel token] client_secret: ${bodyClientSecret.slice(0, 4)}****`);
|
|
2319
|
-
debug(
|
|
2484
|
+
debug(
|
|
2485
|
+
"vercel.oauth",
|
|
2486
|
+
`[Vercel token] code_verifier: ${code_verifier ? code_verifier.slice(0, 8) + "..." : "undefined"}`
|
|
2487
|
+
);
|
|
2320
2488
|
const integrationsConfigured = vs.integrations.all().length > 0;
|
|
2321
2489
|
if (integrationsConfigured) {
|
|
2322
2490
|
const integration = vs.integrations.findOneBy("client_id", bodyClientId);
|
|
2323
2491
|
if (!integration) {
|
|
2324
2492
|
debug("vercel.oauth", `[Vercel token] REJECTED: client_id not found`);
|
|
2325
|
-
return c.json(
|
|
2493
|
+
return c.json(
|
|
2494
|
+
{ error: "invalid_client", error_description: "The client_id and/or client_secret passed are incorrect." },
|
|
2495
|
+
401
|
|
2496
|
+
);
|
|
2326
2497
|
}
|
|
2327
2498
|
if (!constantTimeSecretEqual(bodyClientSecret, integration.client_secret)) {
|
|
2328
2499
|
debug("vercel.oauth", `[Vercel token] REJECTED: client_secret mismatch`);
|
|
2329
|
-
return c.json(
|
|
2500
|
+
return c.json(
|
|
2501
|
+
{ error: "invalid_client", error_description: "The client_id and/or client_secret passed are incorrect." },
|
|
2502
|
+
401
|
|
2503
|
+
);
|
|
2330
2504
|
}
|
|
2331
2505
|
debug("vercel.oauth", `[Vercel token] client credentials OK (${integration.name})`);
|
|
2332
2506
|
}
|
|
2333
2507
|
const pending = pendingCodes.get(code);
|
|
2334
2508
|
if (!pending) {
|
|
2335
2509
|
debug("vercel.oauth", `[Vercel token] REJECTED: code not found in pendingCodes`);
|
|
2336
|
-
return c.json(
|
|
2337
|
-
{ error: "invalid_grant", error_description: "The code passed is incorrect or expired." },
|
|
2338
|
-
400
|
|
2339
|
-
);
|
|
2510
|
+
return c.json({ error: "invalid_grant", error_description: "The code passed is incorrect or expired." }, 400);
|
|
2340
2511
|
}
|
|
2341
2512
|
if (isPendingCodeExpired(pending)) {
|
|
2342
2513
|
debug("vercel.oauth", `[Vercel token] REJECTED: code expired`);
|
|
2343
2514
|
pendingCodes.delete(code);
|
|
2344
|
-
return c.json(
|
|
2345
|
-
{ error: "invalid_grant", error_description: "The code passed is incorrect or expired." },
|
|
2346
|
-
400
|
|
2347
|
-
);
|
|
2515
|
+
return c.json({ error: "invalid_grant", error_description: "The code passed is incorrect or expired." }, 400);
|
|
2348
2516
|
}
|
|
2349
2517
|
debug("vercel.oauth", `[Vercel token] code valid, username=${pending.username}, scope=${pending.scope}`);
|
|
2350
2518
|
if (redirect_uri && pending.redirectUri && redirect_uri !== pending.redirectUri) {
|
|
2351
|
-
debug(
|
|
2519
|
+
debug(
|
|
2520
|
+
"vercel.oauth",
|
|
2521
|
+
`[Vercel token] REJECTED: redirect_uri mismatch (got "${redirect_uri}", expected "${pending.redirectUri}")`
|
|
2522
|
+
);
|
|
2352
2523
|
pendingCodes.delete(code);
|
|
2353
2524
|
return c.json(
|
|
2354
|
-
{
|
|
2525
|
+
{
|
|
2526
|
+
error: "invalid_grant",
|
|
2527
|
+
error_description: "The redirect_uri does not match the one used during authorization."
|
|
2528
|
+
},
|
|
2355
2529
|
400
|
|
2356
2530
|
);
|
|
2357
2531
|
}
|
|
2358
2532
|
if (pending.codeChallenge != null) {
|
|
2359
2533
|
if (code_verifier === void 0) {
|
|
2360
|
-
return c.json(
|
|
2361
|
-
{ error: "invalid_grant", error_description: "PKCE verification failed." },
|
|
2362
|
-
400
|
|
2363
|
-
);
|
|
2534
|
+
return c.json({ error: "invalid_grant", error_description: "PKCE verification failed." }, 400);
|
|
2364
2535
|
}
|
|
2365
2536
|
const method = (pending.codeChallengeMethod ?? "plain").toLowerCase();
|
|
2366
2537
|
if (method === "s256") {
|
|
2367
2538
|
const expected = createHash("sha256").update(code_verifier).digest("base64url");
|
|
2368
2539
|
if (expected !== pending.codeChallenge) {
|
|
2369
|
-
return c.json(
|
|
2370
|
-
{ error: "invalid_grant", error_description: "PKCE verification failed." },
|
|
2371
|
-
400
|
|
2372
|
-
);
|
|
2540
|
+
return c.json({ error: "invalid_grant", error_description: "PKCE verification failed." }, 400);
|
|
2373
2541
|
}
|
|
2374
2542
|
} else if (method === "plain") {
|
|
2375
2543
|
if (code_verifier !== pending.codeChallenge) {
|
|
2376
|
-
return c.json(
|
|
2377
|
-
{ error: "invalid_grant", error_description: "PKCE verification failed." },
|
|
2378
|
-
400
|
|
2379
|
-
);
|
|
2544
|
+
return c.json({ error: "invalid_grant", error_description: "PKCE verification failed." }, 400);
|
|
2380
2545
|
}
|
|
2381
2546
|
} else {
|
|
2382
|
-
return c.json(
|
|
2383
|
-
{ error: "invalid_grant", error_description: "PKCE verification failed." },
|
|
2384
|
-
400
|
|
2385
|
-
);
|
|
2547
|
+
return c.json({ error: "invalid_grant", error_description: "PKCE verification failed." }, 400);
|
|
2386
2548
|
}
|
|
2387
2549
|
}
|
|
2388
2550
|
debug("vercel.oauth", `[Vercel token] PKCE OK (challenge=${pending.codeChallenge ? "present" : "none"})`);
|
|
@@ -2400,7 +2562,10 @@ function oauthRoutes({ app, store, tokenMap }) {
|
|
|
2400
2562
|
if (tokenMap) {
|
|
2401
2563
|
tokenMap.set(token, { login: user.username, id: user.id, scopes });
|
|
2402
2564
|
}
|
|
2403
|
-
debug(
|
|
2565
|
+
debug(
|
|
2566
|
+
"vercel.oauth",
|
|
2567
|
+
`[Vercel token] SUCCESS: issued token for ${user.username} (scopes: ${scopes.join(",") || "none"})`
|
|
2568
|
+
);
|
|
2404
2569
|
return c.json({
|
|
2405
2570
|
access_token: token,
|
|
2406
2571
|
token_type: "Bearer",
|
|
@@ -2681,4 +2846,4 @@ export {
|
|
|
2681
2846
|
seedFromConfig,
|
|
2682
2847
|
vercelPlugin
|
|
2683
2848
|
};
|
|
2684
|
-
//# sourceMappingURL=dist-
|
|
2849
|
+
//# sourceMappingURL=dist-4X2KPMAJ.js.map
|