| 1 | import { ProviderSetupError, type CodexAuthCallbackInput } from "@t3tools/contracts"; |
| 2 | import { receiveCodexAuthCallback } from "@t3tools/shared/codexAuthCallback"; |
| 3 | import { codexAuthorizationRequest } from "@t3tools/shared/codexAuthHandoff"; |
| 4 | import { providerAuthReturnUrl } from "@t3tools/shared/providerAuthReturnUrl"; |
| 5 | import { isLoopbackHost } from "@t3tools/shared/preview"; |
| 6 | import * as Deferred from "effect/Deferred"; |
| 7 | import * as Effect from "effect/Effect"; |
| 8 | import * as Fiber from "effect/Fiber"; |
| 9 | import * as Stream from "effect/Stream"; |
| 10 | |
| 11 | /** A connected local environment receives the callback; only the remote environment owns tokens. */ |
| 12 | export function subscribeCodexAuthCallback(input: CodexAuthCallbackInput) { |
| 13 | const failure = (error: unknown) => |
| 14 | new ProviderSetupError({ |
| 15 | instanceId: input.instanceId, |
| 16 | operation: "callback", |
| 17 | detail: |
| 18 | error instanceof Error ? error.message : "Could not receive sign-in on this computer.", |
| 19 | }); |
| 20 | return Stream.unwrap( |
| 21 | Effect.gen(function* () { |
| 22 | const destination = yield* Effect.try({ |
| 23 | try: () => { |
| 24 | codexAuthorizationRequest(input.authorizationUrl); |
| 25 | const destination = providerAuthReturnUrl(input.returnUrl); |
| 26 | if (!destination || !isLoopbackHost(new URL(destination).hostname)) |
| 27 | throw new Error("The local sign-in receiver needs a local T3 Code return address."); |
| 28 | return destination; |
| 29 | }, |
| 30 | catch: failure, |
| 31 | }); |
| 32 | const ready = yield* Deferred.make<void, ProviderSetupError>(); |
| 33 | const runSync = Effect.runSyncWith(yield* Effect.context<never>()); |
| 34 | const callback = yield* Effect.tryPromise({ |
| 35 | try: (signal) => |
| 36 | receiveCodexAuthCallback( |
| 37 | input.authorizationUrl, |
| 38 | async () => { |
| 39 | runSync(Deferred.succeed(ready, undefined)); |
| 40 | return true; |
| 41 | }, |
| 42 | () => destination, |
| 43 | signal, |
| 44 | ), |
| 45 | catch: failure, |
| 46 | }).pipe( |
| 47 | Effect.tapError((error) => Deferred.fail(ready, error)), |
| 48 | Effect.forkScoped, |
| 49 | ); |
| 50 | return Stream.fromEffect(Deferred.await(ready)).pipe( |
| 51 | Stream.map(() => ({ phase: "ready" as const })), |
| 52 | Stream.concat( |
| 53 | Stream.fromEffect(Fiber.join(callback)).pipe( |
| 54 | Stream.map((callbackUrl) => ({ phase: "finished" as const, callbackUrl })), |
| 55 | ), |
| 56 | ), |
| 57 | ); |
| 58 | }), |
| 59 | ); |
| 60 | } |