( connection: ExecutorServerConnection, )
| 751 | const OAUTH_REFRESH_SKEW_SECONDS = 60; |
| 752 | |
| 753 | const refreshOAuthConnection = ( |
| 754 | connection: ExecutorServerConnection, |
| 755 | ): Effect.Effect<ExecutorServerConnection, never, FileSystem.FileSystem | PlatformPath.Path> => |
| 756 | Effect.gen(function* () { |
| 757 | const auth = connection.auth; |
| 758 | if (!auth || auth.kind !== "oauth") return connection; |
| 759 | const now = Math.floor(Date.now() / 1000); |
| 760 | if (auth.expiresAt && auth.expiresAt - now > OAUTH_REFRESH_SKEW_SECONDS) return connection; |
| 761 | // Destructure so the narrowed string types survive into the deferred |
| 762 | // `tryPromise` callback (where TS would otherwise re-widen the fields). |
| 763 | const { refreshToken, tokenEndpoint, clientId } = auth; |
| 764 | if (!refreshToken || !tokenEndpoint || !clientId) return connection; |
| 765 | |
| 766 | const refreshed = yield* Effect.tryPromise({ |
| 767 | try: () => refreshDeviceTokens({ tokenEndpoint, clientId, refreshToken }), |
| 768 | catch: toError, |
| 769 | // On a failed refresh, keep the existing token and let the eventual 401 |
| 770 | // surface, better than blocking the command on a transient hiccup. |
| 771 | }).pipe(Effect.option); |
| 772 | if (Option.isNone(refreshed)) return connection; |
| 773 | |
| 774 | const next = refreshed.value; |
| 775 | const nextConnection = normalizeExecutorServerConnection({ |
| 776 | ...connection, |
| 777 | auth: { |
| 778 | kind: "oauth", |
| 779 | accessToken: next.accessToken, |
| 780 | refreshToken: next.refreshToken ?? refreshToken, |
| 781 | ...(next.expiresAt ? { expiresAt: next.expiresAt } : {}), |
| 782 | tokenEndpoint, |
| 783 | clientId, |
| 784 | }, |
| 785 | }); |
| 786 | |
| 787 | const profileName = profileNameFromConnectionKey(connection.key); |
| 788 | if (profileName) { |
| 789 | yield* upsertCliServerConnectionProfile({ |
| 790 | name: profileName, |
| 791 | connection: nextConnection, |
| 792 | makeDefault: false, |
| 793 | }).pipe(Effect.ignore); |
| 794 | } |
| 795 | return nextConnection; |
| 796 | }); |
| 797 | |
| 798 | const resolveExecutorServerConnection = ( |
| 799 | target: ServerTarget, |
no test coverage detected