|
@@ -1,4 +1,4 @@
|
|
|
-import { Clock, Duration, Effect, Layer, Option, Schema, SchemaGetter, ServiceMap } from "effect"
|
|
|
|
|
|
|
+import { Cache, Clock, Duration, Effect, Layer, Option, Schema, SchemaGetter, ServiceMap } from "effect"
|
|
|
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
|
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
|
|
|
|
|
|
|
import { makeRuntime } from "@/effect/run-service"
|
|
import { makeRuntime } from "@/effect/run-service"
|
|
@@ -175,9 +175,8 @@ export namespace Account {
|
|
|
mapAccountServiceError("HTTP request failed"),
|
|
mapAccountServiceError("HTTP request failed"),
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
- const resolveToken = Effect.fnUntraced(function* (row: AccountRow) {
|
|
|
|
|
|
|
+ const refreshToken = Effect.fnUntraced(function* (row: AccountRow) {
|
|
|
const now = yield* Clock.currentTimeMillis
|
|
const now = yield* Clock.currentTimeMillis
|
|
|
- if (row.token_expiry && row.token_expiry > now) return row.access_token
|
|
|
|
|
|
|
|
|
|
const response = yield* executeEffectOk(
|
|
const response = yield* executeEffectOk(
|
|
|
HttpClientRequest.post(`${row.url}/auth/device/token`).pipe(
|
|
HttpClientRequest.post(`${row.url}/auth/device/token`).pipe(
|
|
@@ -208,6 +207,30 @@ export namespace Account {
|
|
|
return parsed.access_token
|
|
return parsed.access_token
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
|
|
+ const refreshTokenCache = yield* Cache.make<AccountID, AccessToken, AccountError>({
|
|
|
|
|
+ capacity: Number.POSITIVE_INFINITY,
|
|
|
|
|
+ timeToLive: Duration.zero,
|
|
|
|
|
+ lookup: Effect.fnUntraced(function* (accountID) {
|
|
|
|
|
+ const maybeAccount = yield* repo.getRow(accountID)
|
|
|
|
|
+ if (Option.isNone(maybeAccount)) {
|
|
|
|
|
+ return yield* Effect.fail(new AccountServiceError({ message: "Account not found during token refresh" }))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const account = maybeAccount.value
|
|
|
|
|
+ const now = yield* Clock.currentTimeMillis
|
|
|
|
|
+ if (account.token_expiry && account.token_expiry > now) return account.access_token
|
|
|
|
|
+
|
|
|
|
|
+ return yield* refreshToken(account)
|
|
|
|
|
+ }),
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ const resolveToken = Effect.fnUntraced(function* (row: AccountRow) {
|
|
|
|
|
+ const now = yield* Clock.currentTimeMillis
|
|
|
|
|
+ if (row.token_expiry && row.token_expiry > now) return row.access_token
|
|
|
|
|
+
|
|
|
|
|
+ return yield* Cache.get(refreshTokenCache, row.id)
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
const resolveAccess = Effect.fnUntraced(function* (accountID: AccountID) {
|
|
const resolveAccess = Effect.fnUntraced(function* (accountID: AccountID) {
|
|
|
const maybeAccount = yield* repo.getRow(accountID)
|
|
const maybeAccount = yield* repo.getRow(accountID)
|
|
|
if (Option.isNone(maybeAccount)) return Option.none()
|
|
if (Option.isNone(maybeAccount)) return Option.none()
|