pipeline-moe 0.1.4 → 0.1.5
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/package.json
CHANGED
package/src/server.ts
CHANGED
|
@@ -718,8 +718,13 @@ async function main(): Promise<void> {
|
|
|
718
718
|
})
|
|
719
719
|
|
|
720
720
|
// Pending manual inputs for in-flight OAuth flows (pasted redirect URL or
|
|
721
|
-
// authorization code), keyed by provider. Resolved by the /login/input route
|
|
722
|
-
|
|
721
|
+
// authorization code), keyed by provider. Resolved by the /login/input route,
|
|
722
|
+
// rejected by DELETE /login (cancel) — rejecting is what makes pi's flow
|
|
723
|
+
// abort and release the localhost callback port instead of waiting forever.
|
|
724
|
+
const pendingOAuthInputs = new Map<
|
|
725
|
+
string,
|
|
726
|
+
{ resolve: (value: string) => void; reject: (err: Error) => void }
|
|
727
|
+
>()
|
|
723
728
|
|
|
724
729
|
// Start OAuth login flow for a provider (device-code or auth URL).
|
|
725
730
|
app.post("/api/providers/:name/login", async (req, res) => {
|
|
@@ -735,9 +740,22 @@ async function main(): Promise<void> {
|
|
|
735
740
|
return
|
|
736
741
|
}
|
|
737
742
|
|
|
743
|
+
// Retrying while a previous flow for this provider is still waiting would
|
|
744
|
+
// collide on pi's fixed callback port (EADDRINUSE) — abort the old flow
|
|
745
|
+
// first so a retry always gets a fresh start.
|
|
746
|
+
const stale = pendingOAuthInputs.get(name)
|
|
747
|
+
if (stale) {
|
|
748
|
+
pendingOAuthInputs.delete(name)
|
|
749
|
+
stale.reject(new Error("Login restarted"))
|
|
750
|
+
await new Promise((r) => setTimeout(r, 100)) // let the old flow release the port
|
|
751
|
+
}
|
|
752
|
+
|
|
738
753
|
// Start the login flow in the background — communicate progress via SSE.
|
|
739
754
|
// Return 202 immediately so the client can wait for SSE events.
|
|
740
755
|
const providerName = name // capture for closure
|
|
756
|
+
// Identity of THIS attempt's pending entry: the finally below must only
|
|
757
|
+
// clear the map when the entry is still ours, never a newer attempt's.
|
|
758
|
+
let myEntry: { resolve: (value: string) => void; reject: (err: Error) => void } | undefined
|
|
741
759
|
setImmediate(async () => {
|
|
742
760
|
try {
|
|
743
761
|
await resolved.authStorage.login(name, {
|
|
@@ -770,8 +788,9 @@ async function main(): Promise<void> {
|
|
|
770
788
|
// is on another machine. The promise resolves when a client POSTs
|
|
771
789
|
// /login/input; cleanup happens in the outer finally.
|
|
772
790
|
onManualCodeInput: () =>
|
|
773
|
-
new Promise<string>((resolve) => {
|
|
774
|
-
|
|
791
|
+
new Promise<string>((resolve, reject) => {
|
|
792
|
+
myEntry = { resolve, reject }
|
|
793
|
+
pendingOAuthInputs.set(providerName, myEntry)
|
|
775
794
|
}),
|
|
776
795
|
onPrompt: async (prompt) => {
|
|
777
796
|
// Ask the clients for input over SSE and wait for /login/input.
|
|
@@ -781,8 +800,9 @@ async function main(): Promise<void> {
|
|
|
781
800
|
message: prompt.message,
|
|
782
801
|
placeholder: (prompt as { placeholder?: string }).placeholder,
|
|
783
802
|
})
|
|
784
|
-
return new Promise<string>((resolve) => {
|
|
785
|
-
|
|
803
|
+
return new Promise<string>((resolve, reject) => {
|
|
804
|
+
myEntry = { resolve, reject }
|
|
805
|
+
pendingOAuthInputs.set(providerName, myEntry)
|
|
786
806
|
})
|
|
787
807
|
},
|
|
788
808
|
onSelect: async () => {
|
|
@@ -814,7 +834,9 @@ async function main(): Promise<void> {
|
|
|
814
834
|
message: msg,
|
|
815
835
|
})
|
|
816
836
|
} finally {
|
|
817
|
-
pendingOAuthInputs.
|
|
837
|
+
if (myEntry && pendingOAuthInputs.get(providerName) === myEntry) {
|
|
838
|
+
pendingOAuthInputs.delete(providerName)
|
|
839
|
+
}
|
|
818
840
|
}
|
|
819
841
|
})
|
|
820
842
|
|
|
@@ -836,7 +858,21 @@ async function main(): Promise<void> {
|
|
|
836
858
|
return
|
|
837
859
|
}
|
|
838
860
|
pendingOAuthInputs.delete(name)
|
|
839
|
-
resolveInput(value)
|
|
861
|
+
resolveInput.resolve(value)
|
|
862
|
+
res.json({ ok: true })
|
|
863
|
+
})
|
|
864
|
+
|
|
865
|
+
// Cancel an in-flight OAuth login: rejecting the pending input makes pi's
|
|
866
|
+
// flow abort and release its localhost callback port.
|
|
867
|
+
app.delete("/api/providers/:name/login", (req, res) => {
|
|
868
|
+
const name = req.params.name
|
|
869
|
+
const pending = pendingOAuthInputs.get(name)
|
|
870
|
+
if (!pending) {
|
|
871
|
+
res.status(404).json({ error: `no OAuth flow in flight for "${name}"` })
|
|
872
|
+
return
|
|
873
|
+
}
|
|
874
|
+
pendingOAuthInputs.delete(name)
|
|
875
|
+
pending.reject(new Error("Login cancelled"))
|
|
840
876
|
res.json({ ok: true })
|
|
841
877
|
})
|
|
842
878
|
|