- Delete old Vite+Svelte frontend - Initialize new SvelteKit project with TypeScript - Configure Tailwind CSS v4 + DaisyUI - Implement JWT authentication with auto-refresh - Create login page with form validation (Zod) - Add protected route guards - Update Docker configuration for single-stage build - Add E2E tests with Playwright (6/11 passing) - Fix Svelte 5 reactivity with $state() runes Known issues: - 5 E2E tests failing (timing/async issues) - Token refresh implementation needs debugging - Validation error display timing
115 lines
3.9 KiB
TypeScript
115 lines
3.9 KiB
TypeScript
import type * as Effect from "../Effect.js"
|
|
import { dual, pipe } from "../Function.js"
|
|
import * as Option from "../Option.js"
|
|
import type * as Synchronized from "../SynchronizedRef.js"
|
|
import * as core from "./core.js"
|
|
|
|
/** @internal */
|
|
export const getAndUpdateEffect = dual<
|
|
<A, R, E>(f: (a: A) => Effect.Effect<A, E, R>) => (self: Synchronized.SynchronizedRef<A>) => Effect.Effect<A, E, R>,
|
|
<A, R, E>(self: Synchronized.SynchronizedRef<A>, f: (a: A) => Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
|
|
>(2, (self, f) =>
|
|
self.modifyEffect(
|
|
(value) => core.map(f(value), (result) => [value, result] as const)
|
|
))
|
|
|
|
/** @internal */
|
|
export const getAndUpdateSomeEffect = dual<
|
|
<A, R, E>(
|
|
pf: (a: A) => Option.Option<Effect.Effect<A, E, R>>
|
|
) => (self: Synchronized.SynchronizedRef<A>) => Effect.Effect<A, E, R>,
|
|
<A, R, E>(
|
|
self: Synchronized.SynchronizedRef<A>,
|
|
pf: (a: A) => Option.Option<Effect.Effect<A, E, R>>
|
|
) => Effect.Effect<A, E, R>
|
|
>(2, (self, pf) =>
|
|
self.modifyEffect((value) => {
|
|
const result = pf(value)
|
|
switch (result._tag) {
|
|
case "None": {
|
|
return core.succeed([value, value] as const)
|
|
}
|
|
case "Some": {
|
|
return core.map(result.value, (newValue) => [value, newValue] as const)
|
|
}
|
|
}
|
|
}))
|
|
|
|
/** @internal */
|
|
export const modify = dual<
|
|
<A, B>(f: (a: A) => readonly [B, A]) => (self: Synchronized.SynchronizedRef<A>) => Effect.Effect<B>,
|
|
<A, B>(self: Synchronized.SynchronizedRef<A>, f: (a: A) => readonly [B, A]) => Effect.Effect<B>
|
|
>(2, (self, f) => self.modify(f))
|
|
|
|
/** @internal */
|
|
export const modifyEffect = dual<
|
|
<A, B, E, R>(
|
|
f: (a: A) => Effect.Effect<readonly [B, A], E, R>
|
|
) => (self: Synchronized.SynchronizedRef<A>) => Effect.Effect<B, E, R>,
|
|
<A, B, E, R>(
|
|
self: Synchronized.SynchronizedRef<A>,
|
|
f: (a: A) => Effect.Effect<readonly [B, A], E, R>
|
|
) => Effect.Effect<B, E, R>
|
|
>(2, (self, f) => self.modifyEffect(f))
|
|
|
|
/** @internal */
|
|
export const modifySomeEffect = dual<
|
|
<A, B, R, E>(
|
|
fallback: B,
|
|
pf: (a: A) => Option.Option<Effect.Effect<readonly [B, A], E, R>>
|
|
) => (self: Synchronized.SynchronizedRef<A>) => Effect.Effect<B, E, R>,
|
|
<A, B, R, E>(
|
|
self: Synchronized.SynchronizedRef<A>,
|
|
fallback: B,
|
|
pf: (a: A) => Option.Option<Effect.Effect<readonly [B, A], E, R>>
|
|
) => Effect.Effect<B, E, R>
|
|
>(3, (self, fallback, pf) =>
|
|
self.modifyEffect(
|
|
(value) => pipe(pf(value), Option.getOrElse(() => core.succeed([fallback, value] as const)))
|
|
))
|
|
|
|
/** @internal */
|
|
export const updateEffect = dual<
|
|
<A, R, E>(
|
|
f: (a: A) => Effect.Effect<A, E, R>
|
|
) => (self: Synchronized.SynchronizedRef<A>) => Effect.Effect<void, E, R>,
|
|
<A, R, E>(self: Synchronized.SynchronizedRef<A>, f: (a: A) => Effect.Effect<A, E, R>) => Effect.Effect<void, E, R>
|
|
>(2, (self, f) =>
|
|
self.modifyEffect((value) =>
|
|
core.map(
|
|
f(value),
|
|
(result) => [undefined as void, result] as const
|
|
)
|
|
))
|
|
|
|
/** @internal */
|
|
export const updateAndGetEffect = dual<
|
|
<A, R, E>(f: (a: A) => Effect.Effect<A, E, R>) => (self: Synchronized.SynchronizedRef<A>) => Effect.Effect<A, E, R>,
|
|
<A, R, E>(self: Synchronized.SynchronizedRef<A>, f: (a: A) => Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
|
|
>(2, (self, f) =>
|
|
self.modifyEffect(
|
|
(value) => core.map(f(value), (result) => [result, result] as const)
|
|
))
|
|
|
|
/** @internal */
|
|
export const updateSomeEffect = dual<
|
|
<A, R, E>(
|
|
pf: (a: A) => Option.Option<Effect.Effect<A, E, R>>
|
|
) => (self: Synchronized.SynchronizedRef<A>) => Effect.Effect<void, E, R>,
|
|
<A, R, E>(
|
|
self: Synchronized.SynchronizedRef<A>,
|
|
pf: (a: A) => Option.Option<Effect.Effect<A, E, R>>
|
|
) => Effect.Effect<void, E, R>
|
|
>(2, (self, pf) =>
|
|
self.modifyEffect((value) => {
|
|
const result = pf(value)
|
|
switch (result._tag) {
|
|
case "None": {
|
|
return core.succeed([void 0, value] as const)
|
|
}
|
|
case "Some": {
|
|
return core.map(result.value, (a) => [void 0, a] as const)
|
|
}
|
|
}
|
|
}))
|