@h-rig/server 0.0.6-alpha.10 → 0.0.6-alpha.11
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 +23 -0
- package/dist/src/index.js +620 -241
- package/dist/src/server-helpers/github-api-session-index.js +107 -0
- package/dist/src/server-helpers/github-auth-store.js +68 -24
- package/dist/src/server-helpers/github-user-namespace.js +102 -0
- package/dist/src/server-helpers/http-router.js +538 -159
- package/dist/src/server-helpers/project-registry.js +5 -0
- package/dist/src/server-helpers/run-mutations.js +68 -26
- package/dist/src/server.js +620 -241
- package/package.json +4 -4
|
@@ -115,8 +115,13 @@ function upsertProjectRecord(projectRoot, input) {
|
|
|
115
115
|
function linkProjectCheckout(projectRoot, repoSlug, checkout) {
|
|
116
116
|
return upsertProjectRecord(projectRoot, { repoSlug, checkout });
|
|
117
117
|
}
|
|
118
|
+
function projectRegistryContainsCheckout(projectRoot, checkoutPath) {
|
|
119
|
+
const target = resolve(checkoutPath);
|
|
120
|
+
return Object.values(readRegistry(projectRoot)).some((project) => project.checkouts.some((checkout) => checkout.path ? resolve(checkout.path) === target : false));
|
|
121
|
+
}
|
|
118
122
|
export {
|
|
119
123
|
upsertProjectRecord,
|
|
124
|
+
projectRegistryContainsCheckout,
|
|
120
125
|
normalizeRepoSlug,
|
|
121
126
|
linkProjectCheckout,
|
|
122
127
|
getProjectRecord,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { spawn } from "child_process";
|
|
4
4
|
import { loadConfig } from "@rig/core/load-config";
|
|
5
5
|
import { existsSync as existsSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync4, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
6
|
-
import { dirname as
|
|
6
|
+
import { dirname as dirname6, relative as relative2, resolve as resolve10 } from "path";
|
|
7
7
|
import {
|
|
8
8
|
listAuthorityRuns as listAuthorityRuns7,
|
|
9
9
|
readAuthorityRun as readAuthorityRun8,
|
|
@@ -99,7 +99,7 @@ function normalizeStatus(value) {
|
|
|
99
99
|
|
|
100
100
|
// packages/server/src/server.ts
|
|
101
101
|
import { existsSync as existsSync6, readdirSync, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
|
|
102
|
-
import { dirname as
|
|
102
|
+
import { dirname as dirname5, resolve as resolve8 } from "path";
|
|
103
103
|
import {
|
|
104
104
|
listAuthorityArtifactRoots,
|
|
105
105
|
listAuthorityRuns as listAuthorityRuns6,
|
|
@@ -478,8 +478,8 @@ import {
|
|
|
478
478
|
|
|
479
479
|
// packages/server/src/server-helpers/github-auth-store.ts
|
|
480
480
|
import { randomBytes } from "crypto";
|
|
481
|
-
import { chmodSync, existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
482
|
-
import { resolve as resolve7 } from "path";
|
|
481
|
+
import { chmodSync, copyFileSync, existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
482
|
+
import { dirname as dirname4, resolve as resolve7 } from "path";
|
|
483
483
|
function cleanString(value) {
|
|
484
484
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
485
485
|
}
|
|
@@ -509,6 +509,26 @@ function parseApiSessions(value) {
|
|
|
509
509
|
}];
|
|
510
510
|
});
|
|
511
511
|
}
|
|
512
|
+
function parsePendingDevice(value) {
|
|
513
|
+
if (!value || typeof value !== "object")
|
|
514
|
+
return null;
|
|
515
|
+
const record = value;
|
|
516
|
+
const pollId = cleanString(record.pollId);
|
|
517
|
+
const deviceCode = cleanString(record.deviceCode);
|
|
518
|
+
const expiresAt = cleanString(record.expiresAt);
|
|
519
|
+
const intervalSeconds = typeof record.intervalSeconds === "number" && Number.isFinite(record.intervalSeconds) ? Math.max(1, Math.floor(record.intervalSeconds)) : null;
|
|
520
|
+
if (!pollId || !deviceCode || !expiresAt || !intervalSeconds)
|
|
521
|
+
return null;
|
|
522
|
+
return { pollId, deviceCode, expiresAt, intervalSeconds };
|
|
523
|
+
}
|
|
524
|
+
function parsePendingDevices(value) {
|
|
525
|
+
if (!Array.isArray(value))
|
|
526
|
+
return [];
|
|
527
|
+
return value.flatMap((entry) => {
|
|
528
|
+
const pending = parsePendingDevice(entry);
|
|
529
|
+
return pending ? [pending] : [];
|
|
530
|
+
});
|
|
531
|
+
}
|
|
512
532
|
function readStoredAuth(stateFile) {
|
|
513
533
|
if (!existsSync4(stateFile))
|
|
514
534
|
return {};
|
|
@@ -522,6 +542,7 @@ function readStoredAuth(stateFile) {
|
|
|
522
542
|
selectedRepo: cleanString(parsed.selectedRepo),
|
|
523
543
|
tokenSource: parsed.tokenSource === "oauth-device" || parsed.tokenSource === "manual-token" || parsed.tokenSource === "env" ? parsed.tokenSource : undefined,
|
|
524
544
|
pendingDevice: parsePendingDevice(parsed.pendingDevice),
|
|
545
|
+
pendingDevices: parsePendingDevices(parsed.pendingDevices),
|
|
525
546
|
apiSessions: parseApiSessions(parsed.apiSessions),
|
|
526
547
|
updatedAt: cleanString(parsed.updatedAt) ?? undefined
|
|
527
548
|
};
|
|
@@ -529,34 +550,36 @@ function readStoredAuth(stateFile) {
|
|
|
529
550
|
return {};
|
|
530
551
|
}
|
|
531
552
|
}
|
|
532
|
-
function parsePendingDevice(value) {
|
|
533
|
-
if (!value || typeof value !== "object")
|
|
534
|
-
return null;
|
|
535
|
-
const record = value;
|
|
536
|
-
const pollId = cleanString(record.pollId);
|
|
537
|
-
const deviceCode = cleanString(record.deviceCode);
|
|
538
|
-
const expiresAt = cleanString(record.expiresAt);
|
|
539
|
-
const intervalSeconds = typeof record.intervalSeconds === "number" && Number.isFinite(record.intervalSeconds) ? Math.max(1, Math.floor(record.intervalSeconds)) : null;
|
|
540
|
-
if (!pollId || !deviceCode || !expiresAt || !intervalSeconds)
|
|
541
|
-
return null;
|
|
542
|
-
return { pollId, deviceCode, expiresAt, intervalSeconds };
|
|
543
|
-
}
|
|
544
553
|
function newApiSessionToken() {
|
|
545
554
|
return `rig_${randomBytes(32).toString("base64url")}`;
|
|
546
555
|
}
|
|
547
556
|
function writeStoredAuth(stateFile, payload) {
|
|
548
|
-
mkdirSync4(
|
|
557
|
+
mkdirSync4(dirname4(stateFile), { recursive: true });
|
|
549
558
|
writeFileSync4(stateFile, `${JSON.stringify(payload, null, 2)}
|
|
550
559
|
`, { encoding: "utf8", mode: 384 });
|
|
551
560
|
try {
|
|
552
561
|
chmodSync(stateFile, 384);
|
|
553
562
|
} catch {}
|
|
554
563
|
}
|
|
564
|
+
function localProjectAuthStateFile(projectRoot) {
|
|
565
|
+
return resolve7(projectRoot, ".rig", "state", "github-auth.json");
|
|
566
|
+
}
|
|
555
567
|
function resolveGitHubAuthStateFile(projectRoot) {
|
|
556
568
|
return resolve7(resolveServerAuthorityPaths(projectRoot).stateDir, "github-auth.json");
|
|
557
569
|
}
|
|
558
|
-
function
|
|
559
|
-
const
|
|
570
|
+
function copyGitHubAuthStateToLocalProjectRoot(stateFile, projectRoot) {
|
|
571
|
+
const targetFile = localProjectAuthStateFile(projectRoot);
|
|
572
|
+
mkdirSync4(dirname4(targetFile), { recursive: true });
|
|
573
|
+
if (existsSync4(stateFile)) {
|
|
574
|
+
copyFileSync(stateFile, targetFile);
|
|
575
|
+
try {
|
|
576
|
+
chmodSync(targetFile, 384);
|
|
577
|
+
} catch {}
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
writeStoredAuth(targetFile, {});
|
|
581
|
+
}
|
|
582
|
+
function createGitHubAuthStoreFromStateFile(stateFile) {
|
|
560
583
|
return {
|
|
561
584
|
stateFile,
|
|
562
585
|
status(options) {
|
|
@@ -586,6 +609,7 @@ function createGitHubAuthStore(projectRoot) {
|
|
|
586
609
|
scopes: input.scopes ?? [],
|
|
587
610
|
selectedRepo: input.selectedRepo ?? previous.selectedRepo ?? null,
|
|
588
611
|
pendingDevice: null,
|
|
612
|
+
pendingDevices: [],
|
|
589
613
|
apiSessions: previous.apiSessions ?? [],
|
|
590
614
|
updatedAt: new Date().toISOString()
|
|
591
615
|
});
|
|
@@ -614,15 +638,24 @@ function createGitHubAuthStore(projectRoot) {
|
|
|
614
638
|
const session = (previous.apiSessions ?? []).find((candidate) => candidate.token === clean);
|
|
615
639
|
return session ? { login: cleanString(session.login), userId: cleanString(session.userId) } : null;
|
|
616
640
|
},
|
|
617
|
-
copyToProjectRoot(
|
|
618
|
-
const targetFile = resolveGitHubAuthStateFile(
|
|
641
|
+
copyToProjectRoot(projectRoot) {
|
|
642
|
+
const targetFile = resolveGitHubAuthStateFile(projectRoot);
|
|
619
643
|
writeStoredAuth(targetFile, readStoredAuth(stateFile));
|
|
620
644
|
},
|
|
645
|
+
copyToLocalProjectRoot(projectRoot) {
|
|
646
|
+
copyGitHubAuthStateToLocalProjectRoot(stateFile, projectRoot);
|
|
647
|
+
},
|
|
621
648
|
savePendingDevice(input) {
|
|
622
649
|
const previous = readStoredAuth(stateFile);
|
|
650
|
+
const pendingDevices = [
|
|
651
|
+
...previous.pendingDevice ? [previous.pendingDevice] : [],
|
|
652
|
+
...previous.pendingDevices ?? [],
|
|
653
|
+
input
|
|
654
|
+
].filter((entry, index, entries) => entries.findIndex((candidate) => candidate.pollId === entry.pollId) === index);
|
|
623
655
|
writeStoredAuth(stateFile, {
|
|
624
656
|
...previous,
|
|
625
|
-
pendingDevice:
|
|
657
|
+
pendingDevice: null,
|
|
658
|
+
pendingDevices,
|
|
626
659
|
updatedAt: new Date().toISOString()
|
|
627
660
|
});
|
|
628
661
|
},
|
|
@@ -635,23 +668,32 @@ function createGitHubAuthStore(projectRoot) {
|
|
|
635
668
|
});
|
|
636
669
|
},
|
|
637
670
|
readPendingDevice(pollId) {
|
|
638
|
-
const
|
|
639
|
-
|
|
671
|
+
const previous = readStoredAuth(stateFile);
|
|
672
|
+
const pending = [
|
|
673
|
+
...previous.pendingDevice ? [previous.pendingDevice] : [],
|
|
674
|
+
...previous.pendingDevices ?? []
|
|
675
|
+
].find((entry) => entry.pollId === pollId) ?? null;
|
|
676
|
+
if (!pending)
|
|
640
677
|
return null;
|
|
641
678
|
if (Date.parse(pending.expiresAt) <= Date.now())
|
|
642
679
|
return null;
|
|
643
680
|
return pending;
|
|
644
681
|
},
|
|
645
|
-
clearPendingDevice() {
|
|
682
|
+
clearPendingDevice(pollId) {
|
|
646
683
|
const previous = readStoredAuth(stateFile);
|
|
684
|
+
const remaining = pollId ? (previous.pendingDevices ?? []).filter((entry) => entry.pollId !== pollId) : [];
|
|
647
685
|
writeStoredAuth(stateFile, {
|
|
648
686
|
...previous,
|
|
649
687
|
pendingDevice: null,
|
|
688
|
+
pendingDevices: remaining,
|
|
650
689
|
updatedAt: new Date().toISOString()
|
|
651
690
|
});
|
|
652
691
|
}
|
|
653
692
|
};
|
|
654
693
|
}
|
|
694
|
+
function createGitHubAuthStore(projectRoot) {
|
|
695
|
+
return createGitHubAuthStoreFromStateFile(resolveGitHubAuthStateFile(projectRoot));
|
|
696
|
+
}
|
|
655
697
|
|
|
656
698
|
// packages/server/src/server-helpers/github-projects.ts
|
|
657
699
|
function asRecord(value) {
|
|
@@ -1665,7 +1707,7 @@ function resolveLocalRunCliProjectRoot(projectRoot) {
|
|
|
1665
1707
|
}
|
|
1666
1708
|
try {
|
|
1667
1709
|
const monorepoRoot = resolveMonorepoRoot6(projectRoot);
|
|
1668
|
-
const outerProjectRoot =
|
|
1710
|
+
const outerProjectRoot = dirname6(dirname6(monorepoRoot));
|
|
1669
1711
|
if (existsSync7(resolve10(outerProjectRoot, "packages/cli/bin/rig.ts"))) {
|
|
1670
1712
|
return outerProjectRoot;
|
|
1671
1713
|
}
|