Compare commits

...

1 Commits

Author SHA1 Message Date
Kit Langton 2efc73f12d refactor(core): flatten state transformations 2026-08-21 13:25:42 -04:00
3 changed files with 24 additions and 31 deletions
+10 -15
View File
@@ -109,16 +109,11 @@ export const layer = Layer.effect(
},
)
const find = Effect.fn("Form.find")(function* (id: ID) {
return yield* Cache.getSuccess(forms, id).pipe(
Effect.flatMap((entry) =>
Option.match(entry, {
onNone: () => Effect.fail(new NotFoundError({ id })),
onSome: Effect.succeed,
}),
),
)
})
const requireEntry = Effect.fn("Form.requireEntry")((id: ID) =>
Cache.getSuccess(forms, id).pipe(
Effect.flatMap((entry) => Effect.fromOption(entry, () => new NotFoundError({ id }))),
),
)
const create = Effect.fn("Form.create")((input: CreateInput) =>
Effect.uninterruptible(
@@ -151,7 +146,7 @@ export const layer = Layer.effect(
Effect.uninterruptibleMask((restore) =>
Effect.gen(function* () {
const form = yield* create(input)
const entry = yield* find(form.id).pipe(Effect.orDie)
const entry = yield* requireEntry(form.id).pipe(Effect.orDie)
return yield* restore(Deferred.await(entry.deferred)).pipe(
Effect.onInterrupt(() => Effect.ignore(cancel(form.id))),
)
@@ -160,7 +155,7 @@ export const layer = Layer.effect(
)
const get = Effect.fn("Form.get")(function* (id: ID) {
return (yield* find(id)).form
return (yield* requireEntry(id)).form
})
const list = Effect.fn("Form.list")(function* (input?: ListInput) {
@@ -172,13 +167,13 @@ export const layer = Layer.effect(
})
const state = Effect.fn("Form.state")(function* (id: ID) {
return (yield* find(id)).state
return (yield* requireEntry(id)).state
})
const reply = Effect.fn("Form.reply")((input: ReplyInput) =>
Effect.uninterruptible(
Effect.gen(function* () {
const entry = yield* find(input.id)
const entry = yield* requireEntry(input.id)
if (entry.state.status !== "pending") return yield* new AlreadySettledError({ id: input.id })
const invalid = validateAnswer(entry.form.fields, input.answer)
if (invalid) return yield* new InvalidAnswerError({ id: input.id, message: invalid })
@@ -197,7 +192,7 @@ export const layer = Layer.effect(
const cancel = Effect.fn("Form.cancel")((id: ID) =>
Effect.uninterruptible(
Effect.gen(function* () {
const entry = yield* find(id)
const entry = yield* requireEntry(id)
if (entry.state.status !== "pending") return yield* new AlreadySettledError({ id })
const next: TerminalState = { status: "cancelled" }
yield* bus.publish(Form.Event.Cancelled, { id, sessionID: entry.form.sessionID })
+8 -8
View File
@@ -42,18 +42,18 @@ export function update(adapter: Adapter, event: SessionEvent.DurableEvent) {
const updateOwnedAssistant = (messageID: SessionMessage.ID, recipe: (draft: DraftAssistant) => void) =>
Effect.gen(function* () {
const assistant = yield* adapter.getAssistant(messageID)
if (assistant) yield* adapter.updateAssistant(produce(assistant, recipe))
if (!assistant) return
yield* adapter.updateAssistant(produce(assistant, recipe))
})
const clearCurrentRetry = Effect.gen(function* () {
const assistant = yield* adapter.getCurrentAssistant()
if (assistant?.retry) {
yield* adapter.updateAssistant(
produce(assistant, (draft) => {
draft.retry = undefined
}),
)
}
if (!assistant?.retry) return
yield* adapter.updateAssistant(
produce(assistant, (draft) => {
draft.retry = undefined
}),
)
})
const project = pipe(
+6 -8
View File
@@ -89,15 +89,14 @@ export function create<State, DraftApi>(options: Options<State, DraftApi>): Inte
if (options.finalize) yield* options.finalize(options.draft(next))
})
const apply = (transform: TransformCallback<DraftApi>, draft: DraftApi) =>
Effect.sync(() => {
transform(draft)
})
const materialize = Effect.fnUntraced(function* () {
const next = options.initial()
const api = options.draft(next)
for (const transform of transforms) yield* apply(transform.run, api)
for (const transform of transforms) {
yield* Effect.sync(() => {
transform.run(api)
})
}
yield* commit(next)
})
@@ -135,7 +134,7 @@ export function create<State, DraftApi>(options: Options<State, DraftApi>): Inte
return yield* Deferred.await(done)
})
const result: Interface<State, DraftApi> = {
return {
get: () => state,
transform: Effect.fn("State.transform")(function* (update) {
yield* Effect.annotateCurrentSpan("state", options.name ?? "anonymous")
@@ -176,5 +175,4 @@ export function create<State, DraftApi>(options: Options<State, DraftApi>): Inte
}),
reload,
}
return result
}