@elysiumjs/ariadne (英语)
多步骤流动 极乐世界 应用,例如有密码检查或退票的注册. 一个流的状态会停留在服务器的步数之间,每个步数都会运行一次:重复的步数id重放所存储的答案.
安装
bun add @elysiumjs/ariadne
宣布一个流
一个流是控制器。 每个步骤都是 POST 它的路线,所以 @Http.*() 参数装饰器在任何路线上都一样的一步上工作.
import type { Static } from '@elysiumjs/core';
import { Flow } from '@elysiumjs/ariadne';
import { BadRequestError, Http, t } from '@elysiumjs/core';
type SignUp = { email?: string; attempts: number };
const EmailBody = t.Object({ email: t.String({ format: 'email' }) });
const CodeBody = t.Object({ code: t.String() });
@Flow.controller('sign-up', { ttl: 900, owner: 'guest' })
export class SignUpFlow {
constructor(
private readonly codes: CodeService,
private readonly users: UserService
) {}
@Flow.initial()
public initial(): SignUp {
return { attempts: 0 };
}
@Flow.step({ next: ['code'], back: ['email'] })
public async email(
@Http.body(EmailBody) { email }: Static<typeof EmailBody>,
@Flow.state() state: SignUp
) {
await this.codes.send(email);
return Flow.advance({ ...state, email }, { sentTo: email });
}
@Flow.step()
public async code(
@Http.body(CodeBody) { code }: Static<typeof CodeBody>,
@Flow.state() state: SignUp
) {
if (!(await this.codes.check(state.email!, code))) {
const attempts = state.attempts + 1;
return Flow.refuse({ ...state, attempts }, new BadRequestError('Wrong code.'), {
end: attempts >= 3
});
}
return { userId: await this.users.create(state.email!) };
}
}
next列出可能遵循该步骤的步骤,或该步骤所产生的状态的函数。 流量在不给出步骤时会结束,这就是默认.back列出客户可能从那里再次提交的较早步骤,以及onRewind(state, ctx)运行在再次提交的步骤状态.ttl流动在它的最后一步, 几秒钟后,会活多久。 它可能是从配置中读取它的一个函数,每次一个流量开始或一个步骤被承诺时都称为.start列出首先接受的步骤,并默认为第一个宣布的步骤.name命名一个步骤,以取代它的方法.@Flow.initial()标记第一步之前建立状态的方法。 没有它,国家开始是{}。 。 。 .@Flow.state()注入状态,和@Flow.context()流动,它的钥匙, 步骤的id和所有者.Flow.advance(state, answer)向前移动。 一个还原其他东西的步骤会回答它并保持状态.- 步骤可能返回 a
Result(或一个AsyncResult:一个经过一次就算它的价值,一个失败的人以其错误拒绝一步,就像返回或抛出DomainError。 。 。 . Flow.refuse(state, error)拒绝该步骤但保持其状态,如计数尝试。 与{ end: true },该流量被删除.- 扔出一无所犯步骤,客户端可以重试同一步骤的ID.
- 呈文将维持其步骤
lease秒(默认为30个)在运行时,步骤运行在商店当时持有的状态上,因此试图让比赛看到对方的拒绝. 重试一个超过租赁期的呈文 将步子再次延伸 所以步子可能更长lease。 。 。 .
其他选择 @Http.controller() 适用于 @Flow.controller(),以及路由装饰者到 @Flow.step()。 护卫、 速率限制、 拦截器和过滤器像任何控制器一样装饰一流.
流动
import { AriadneModule } from '@elysiumjs/ariadne';
import { RedisFlowStore } from '@elysiumjs/ariadne-redis';
import { Application, Module } from '@elysiumjs/core';
@Module.register({ controllers: [SignUpFlow, ChangeEmailFlow] })
class AccountModule extends Module {}
@Application.register({
modules: [
AriadneModule.with({ store: new RedisFlowStore({ connection: () => Redis.connection() }) }),
AccountModule
]
})
class App extends Application {}
下方的流程答案 path,默认为 /flows/{name}数字 :
| 路线 | 页眉 | 答复 |
|---|---|---|
POST /flows/{flow} | 201 (韩语) { flowKey, owner?, nextSteps, backSteps } | |
GET /flows/{flow} | x-flow-key | { flowKey, step, nextSteps, backSteps, answer } |
POST /flows/{flow}/{step} | x-flow-key, (中文(简体) ), x-flow-step | { answer, nextSteps, backSteps } |
x-flow-step是提交文件的id,客户端选择并再次发送以重试.- A 类
guest属于owner符号在起始时响应 。 以后打来电话送来x-flow-owner头曰. - A 类
user流程属于已签名的用户,所以其控制器需要一个守护,例如@Auth()从他们.user在模块选项中从上下文读取用户 ID。 默认是currentUser,哪个@Auth()设置:当用户是字符串时,用户本身(没有加载器的会话守护),否则其id,否则sub(JWT索赔).
这些路线回答了问题:
- 410 当流量到期,或已完成;
- 409作为一步,流动现在不接受(与
nextSteps, (中文(简体) ),backSteps和最后一个answer)),在另一条流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流流flow-step-in-progress(三); - 403,当调用者不拥有流量,401,对于没有用户的用户流量; 4;
- 422) 对于一个不符合步子的图谋的身体.
- 申请400份,不用
x-flow-key或者说x-flow-step。 。 。 .
存储
MemoryFlowStore,用于测试和单进程应用.RedisFlowStore联 合 国@elysiumjs/ariadne-redis他们的主张和承诺是Lua剧本EVAL厄普斯塔什也运行着.durableFlowStore联 合 国@elysiumjs/ariadne-workers云花板工人的活性物质.
成品流使其最后的回放时间可长达10分钟. 然后只有它的主人和结束时间留下, 对于它的TTL, 以便一个迟到的呼叫得知流结束。 自定义存储工具 FlowStore,并可以跟踪 FlowRules 像其他人一样回答.