gemi 0.123.0 → 0.125.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/AgentController.d.ts +185 -3
- package/dist/ai/AgentController.d.ts.map +1 -1
- package/dist/ai/client/index.d.ts +1 -1
- package/dist/ai/client/index.d.ts.map +1 -1
- package/dist/ai/client/index.js +38 -9
- package/dist/ai/client/index.js.map +1 -1
- package/dist/ai/client/reducer.d.ts.map +1 -1
- package/dist/ai/index.d.ts +2 -2
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +31 -48
- package/dist/ai/index.js.map +6 -15
- package/dist/ai/types.d.ts +26 -0
- package/dist/ai/types.d.ts.map +1 -1
- package/dist/ai/useChat.d.ts +35 -2
- package/dist/ai/useChat.d.ts.map +1 -1
- package/dist/app/index.js +1 -1
- package/dist/auth/AuthController.d.ts.map +1 -1
- package/dist/auth/AuthManager.d.ts +11 -0
- package/dist/auth/AuthManager.d.ts.map +1 -1
- package/dist/auth/AuthServiceProvider.d.ts +2 -0
- package/dist/auth/AuthServiceProvider.d.ts.map +1 -1
- package/dist/auth/config.d.ts +71 -2
- package/dist/auth/config.d.ts.map +1 -1
- package/dist/auth/oauth/providers.d.ts +10 -0
- package/dist/auth/oauth/providers.d.ts.map +1 -0
- package/dist/bun/plugin.js +1 -1
- package/dist/bun/preload.js +1 -1
- package/dist/{chunk-fyk07w01.js → chunk-0x1s02r1.js} +3 -3
- package/dist/{chunk-fyk07w01.js.map → chunk-0x1s02r1.js.map} +1 -1
- package/dist/{chunk-ycsrpf47.js → chunk-1jcngq6w.js} +3 -3
- package/dist/{chunk-ycsrpf47.js.map → chunk-1jcngq6w.js.map} +1 -1
- package/dist/{chunk-gwnmgkq5.js → chunk-1mxb44n9.js} +2 -2
- package/dist/{chunk-gwnmgkq5.js.map → chunk-1mxb44n9.js.map} +1 -1
- package/dist/{chunk-y67evsdy.js → chunk-1n40bdxf.js} +2 -2
- package/dist/{chunk-y67evsdy.js.map → chunk-1n40bdxf.js.map} +1 -1
- package/dist/chunk-1xmh61fg.js +5 -0
- package/dist/{chunk-tazvfppr.js.map → chunk-1xmh61fg.js.map} +1 -1
- package/dist/{chunk-sxa70wgn.js → chunk-3br5zr7a.js} +3 -3
- package/dist/{chunk-sxa70wgn.js.map → chunk-3br5zr7a.js.map} +1 -1
- package/dist/{chunk-w61sphn5.js → chunk-3kxe9geg.js} +3 -3
- package/dist/{chunk-w61sphn5.js.map → chunk-3kxe9geg.js.map} +1 -1
- package/dist/{chunk-w0jfqnw9.js → chunk-5fh4pvyt.js} +2 -2
- package/dist/{chunk-w0jfqnw9.js.map → chunk-5fh4pvyt.js.map} +1 -1
- package/dist/{chunk-hnrzm5pf.js → chunk-6gwxvmjv.js} +3 -3
- package/dist/{chunk-hnrzm5pf.js.map → chunk-6gwxvmjv.js.map} +1 -1
- package/dist/{chunk-j0cnsgjq.js → chunk-6q6bhkyf.js} +1 -1
- package/dist/{chunk-5a4qbtez.js → chunk-6vz75swk.js} +2 -2
- package/dist/{chunk-5a4qbtez.js.map → chunk-6vz75swk.js.map} +1 -1
- package/dist/chunk-6wgh7nk6.js +15 -0
- package/dist/{chunk-z23h4s1a.js.map → chunk-6wgh7nk6.js.map} +6 -5
- package/dist/chunk-7vrrgxwm.js +22 -0
- package/dist/chunk-7vrrgxwm.js.map +21 -0
- package/dist/{chunk-kvas36p6.js → chunk-7zj6bk9a.js} +2 -2
- package/dist/{chunk-kvas36p6.js.map → chunk-7zj6bk9a.js.map} +1 -1
- package/dist/{chunk-kdjhgtp9.js → chunk-8tvfmy1a.js} +4 -4
- package/dist/{chunk-kdjhgtp9.js.map → chunk-8tvfmy1a.js.map} +1 -1
- package/dist/{chunk-vd6zn8c4.js → chunk-910p6ne6.js} +2 -2
- package/dist/{chunk-vd6zn8c4.js.map → chunk-910p6ne6.js.map} +1 -1
- package/dist/{chunk-96a1459v.js → chunk-ap3g6rbw.js} +2 -2
- package/dist/{chunk-96a1459v.js.map → chunk-ap3g6rbw.js.map} +1 -1
- package/dist/{chunk-4qpypa3h.js → chunk-ayfjjgv2.js} +1 -1
- package/dist/chunk-b4x1dt3s.js +10 -0
- package/dist/chunk-b4x1dt3s.js.map +43 -0
- package/dist/{chunk-aafanq8n.js → chunk-b7a22evs.js} +3 -3
- package/dist/{chunk-aafanq8n.js.map → chunk-b7a22evs.js.map} +1 -1
- package/dist/{chunk-rjtmgbay.js → chunk-bny9s44t.js} +2 -2
- package/dist/{chunk-rjtmgbay.js.map → chunk-bny9s44t.js.map} +1 -1
- package/dist/{chunk-k17wx7gz.js → chunk-by5gwr8x.js} +2 -2
- package/dist/{chunk-k17wx7gz.js.map → chunk-by5gwr8x.js.map} +1 -1
- package/dist/{chunk-53hc0ah1.js → chunk-c0qpv8x7.js} +2 -2
- package/dist/{chunk-53hc0ah1.js.map → chunk-c0qpv8x7.js.map} +1 -1
- package/dist/{chunk-9t08wbkd.js → chunk-cpem1j1x.js} +2 -2
- package/dist/{chunk-9t08wbkd.js.map → chunk-cpem1j1x.js.map} +1 -1
- package/dist/{chunk-vwnd4jb5.js → chunk-crnfxn9n.js} +2 -2
- package/dist/{chunk-vwnd4jb5.js.map → chunk-crnfxn9n.js.map} +1 -1
- package/dist/{chunk-s5jxc63j.js → chunk-cwt8e782.js} +3 -3
- package/dist/{chunk-s5jxc63j.js.map → chunk-cwt8e782.js.map} +1 -1
- package/dist/{chunk-0tc0j3pf.js → chunk-dxyxd7b3.js} +2 -2
- package/dist/{chunk-0tc0j3pf.js.map → chunk-dxyxd7b3.js.map} +1 -1
- package/dist/{chunk-nf608sb1.js → chunk-dy58aztm.js} +2 -2
- package/dist/{chunk-nf608sb1.js.map → chunk-dy58aztm.js.map} +1 -1
- package/dist/chunk-entpqjyn.js +5 -0
- package/dist/chunk-entpqjyn.js.map +10 -0
- package/dist/{chunk-qen6587t.js → chunk-eq5svwca.js} +2 -2
- package/dist/{chunk-qen6587t.js.map → chunk-eq5svwca.js.map} +1 -1
- package/dist/{chunk-n1a2zj5z.js → chunk-erzfs4t2.js} +2 -2
- package/dist/{chunk-n1a2zj5z.js.map → chunk-erzfs4t2.js.map} +3 -3
- package/dist/{chunk-pfm9ngch.js → chunk-ex41d03h.js} +2 -2
- package/dist/{chunk-pfm9ngch.js.map → chunk-ex41d03h.js.map} +1 -1
- package/dist/{chunk-fxxbwyce.js → chunk-ey1xrbaz.js} +2 -2
- package/dist/{chunk-fxxbwyce.js.map → chunk-ey1xrbaz.js.map} +1 -1
- package/dist/chunk-eyptwf54.js +57 -0
- package/dist/{chunk-gvp6brdt.js.map → chunk-eyptwf54.js.map} +25 -22
- package/dist/{chunk-x0jahbqj.js → chunk-g52fcwca.js} +2 -2
- package/dist/{chunk-x0jahbqj.js.map → chunk-g52fcwca.js.map} +1 -1
- package/dist/{chunk-hs88b8gt.js → chunk-ghcvztxn.js} +2 -2
- package/dist/{chunk-hs88b8gt.js.map → chunk-ghcvztxn.js.map} +1 -1
- package/dist/{chunk-rjm1kj8n.js → chunk-gp00enrk.js} +1 -1
- package/dist/{chunk-08fcqny0.js → chunk-h8w9mzjj.js} +6 -6
- package/dist/{chunk-08fcqny0.js.map → chunk-h8w9mzjj.js.map} +7 -7
- package/dist/{chunk-9p7eq7bz.js → chunk-hff9w6rt.js} +2 -2
- package/dist/{chunk-9p7eq7bz.js.map → chunk-hff9w6rt.js.map} +1 -1
- package/dist/{chunk-ay8nat73.js → chunk-hxn0s3zh.js} +2 -2
- package/dist/{chunk-ay8nat73.js.map → chunk-hxn0s3zh.js.map} +1 -1
- package/dist/{chunk-de7hxe73.js → chunk-hzen9gh4.js} +2 -2
- package/dist/{chunk-de7hxe73.js.map → chunk-hzen9gh4.js.map} +1 -1
- package/dist/{chunk-xhmtph39.js → chunk-j10a0m7q.js} +1 -1
- package/dist/{chunk-wqharhrp.js → chunk-j12hpdxk.js} +1 -1
- package/dist/{chunk-bk2aheea.js → chunk-j5rwv09s.js} +2 -2
- package/dist/{chunk-bk2aheea.js.map → chunk-j5rwv09s.js.map} +1 -1
- package/dist/{chunk-zjej5vqh.js → chunk-jykkqwcy.js} +3 -3
- package/dist/{chunk-zjej5vqh.js.map → chunk-jykkqwcy.js.map} +1 -1
- package/dist/{chunk-9a9ef0f1.js → chunk-k1ebt28j.js} +2 -2
- package/dist/{chunk-9a9ef0f1.js.map → chunk-k1ebt28j.js.map} +1 -1
- package/dist/{chunk-q1e3q01h.js → chunk-kcsa57km.js} +2 -2
- package/dist/{chunk-q1e3q01h.js.map → chunk-kcsa57km.js.map} +1 -1
- package/dist/{chunk-r5tadf14.js → chunk-khdkrfxp.js} +2 -2
- package/dist/{chunk-r5tadf14.js.map → chunk-khdkrfxp.js.map} +1 -1
- package/dist/{chunk-fsy344zb.js → chunk-knq4ack4.js} +2 -2
- package/dist/{chunk-fsy344zb.js.map → chunk-knq4ack4.js.map} +1 -1
- package/dist/{chunk-f1thqe6j.js → chunk-m7pghdcy.js} +2 -2
- package/dist/{chunk-f1thqe6j.js.map → chunk-m7pghdcy.js.map} +1 -1
- package/dist/{chunk-enta97jb.js → chunk-mmqnq1qh.js} +3 -3
- package/dist/{chunk-enta97jb.js.map → chunk-mmqnq1qh.js.map} +1 -1
- package/dist/{chunk-0qmc7snf.js → chunk-n3z83qhq.js} +2 -2
- package/dist/{chunk-0qmc7snf.js.map → chunk-n3z83qhq.js.map} +1 -1
- package/dist/{chunk-mxbtcaed.js → chunk-npbf06c1.js} +2 -2
- package/dist/{chunk-mxbtcaed.js.map → chunk-npbf06c1.js.map} +1 -1
- package/dist/{chunk-6gjvqtcp.js → chunk-p5df4pn7.js} +2 -2
- package/dist/{chunk-6gjvqtcp.js.map → chunk-p5df4pn7.js.map} +1 -1
- package/dist/{chunk-ywgvxx35.js → chunk-p6jbmcrg.js} +2 -2
- package/dist/{chunk-ywgvxx35.js.map → chunk-p6jbmcrg.js.map} +1 -1
- package/dist/{chunk-d3ywmeb7.js → chunk-p7mvp5nf.js} +2 -2
- package/dist/{chunk-d3ywmeb7.js.map → chunk-p7mvp5nf.js.map} +1 -1
- package/dist/{chunk-52xkw2bs.js → chunk-q6ah4yjg.js} +2 -2
- package/dist/{chunk-52xkw2bs.js.map → chunk-q6ah4yjg.js.map} +1 -1
- package/dist/{chunk-6pxavyh3.js → chunk-r923001x.js} +2 -2
- package/dist/{chunk-6pxavyh3.js.map → chunk-r923001x.js.map} +1 -1
- package/dist/{chunk-1f1sb3w7.js → chunk-rany5zgk.js} +2 -2
- package/dist/{chunk-1f1sb3w7.js.map → chunk-rany5zgk.js.map} +1 -1
- package/dist/{chunk-30xxc6r7.js → chunk-rmgkc3a2.js} +2 -2
- package/dist/{chunk-30xxc6r7.js.map → chunk-rmgkc3a2.js.map} +1 -1
- package/dist/{chunk-ebx5hnqn.js → chunk-rvspb96n.js} +3 -3
- package/dist/{chunk-ebx5hnqn.js.map → chunk-rvspb96n.js.map} +1 -1
- package/dist/{chunk-kzstewtm.js → chunk-rwmja4zs.js} +2 -2
- package/dist/{chunk-kzstewtm.js.map → chunk-rwmja4zs.js.map} +1 -1
- package/dist/{chunk-8x73yyfs.js → chunk-s4semb89.js} +1 -1
- package/dist/chunk-s4xg69r9.js +24 -0
- package/dist/{chunk-vpgbn494.js.map → chunk-s4xg69r9.js.map} +2 -2
- package/dist/{chunk-58ffbwdc.js → chunk-stn0a56e.js} +2 -2
- package/dist/{chunk-58ffbwdc.js.map → chunk-stn0a56e.js.map} +1 -1
- package/dist/{chunk-73v34hw8.js → chunk-sv125fqq.js} +2 -2
- package/dist/{chunk-73v34hw8.js.map → chunk-sv125fqq.js.map} +1 -1
- package/dist/{chunk-h76mddt3.js → chunk-t2t63wa0.js} +2 -2
- package/dist/{chunk-h76mddt3.js.map → chunk-t2t63wa0.js.map} +1 -1
- package/dist/{chunk-675kzd7z.js → chunk-t6qpm2j7.js} +2 -2
- package/dist/{chunk-675kzd7z.js.map → chunk-t6qpm2j7.js.map} +1 -1
- package/dist/chunk-tabsxzg9.js +5 -0
- package/dist/chunk-tabsxzg9.js.map +13 -0
- package/dist/{chunk-2vc72qez.js → chunk-vhvvjaj3.js} +3 -3
- package/dist/{chunk-2vc72qez.js.map → chunk-vhvvjaj3.js.map} +1 -1
- package/dist/{chunk-2amj1eyp.js → chunk-x2j84d06.js} +2 -2
- package/dist/{chunk-2amj1eyp.js.map → chunk-x2j84d06.js.map} +1 -1
- package/dist/{chunk-dmj6ysym.js → chunk-xe2pm36q.js} +2 -2
- package/dist/{chunk-dmj6ysym.js.map → chunk-xe2pm36q.js.map} +1 -1
- package/dist/{chunk-rkgsvsrj.js → chunk-xfvegbxn.js} +2 -2
- package/dist/{chunk-rkgsvsrj.js.map → chunk-xfvegbxn.js.map} +1 -1
- package/dist/{chunk-nvngb4ed.js → chunk-y9f2see3.js} +3 -3
- package/dist/{chunk-nvngb4ed.js.map → chunk-y9f2see3.js.map} +1 -1
- package/dist/{chunk-1kdga1b2.js → chunk-yhht1j7f.js} +2 -2
- package/dist/{chunk-1kdga1b2.js.map → chunk-yhht1j7f.js.map} +1 -1
- package/dist/{chunk-eevna943.js → chunk-z5nfve1k.js} +2 -2
- package/dist/chunk-z5nfve1k.js.map +10 -0
- package/dist/{chunk-j8vc3bze.js → chunk-zq5375wd.js} +3 -3
- package/dist/{chunk-j8vc3bze.js.map → chunk-zq5375wd.js.map} +1 -1
- package/dist/chunks/{ThemeProvider-CgK2mmVV.js → ThemeProvider-CS2a1snV.js} +34 -3
- package/dist/chunks/ThemeProvider-CS2a1snV.js.map +1 -0
- package/dist/client/Mutation.d.ts +7 -6
- package/dist/client/Mutation.d.ts.map +1 -1
- package/dist/client/MutationError.d.ts +53 -1
- package/dist/client/MutationError.d.ts.map +1 -1
- package/dist/client/QueryResource.d.ts +9 -0
- package/dist/client/QueryResource.d.ts.map +1 -1
- package/dist/client/auth/useEmailCode.d.ts +3 -3
- package/dist/client/auth/useForgotPassword.d.ts +1 -1
- package/dist/client/auth/useResetPassword.d.ts +1 -1
- package/dist/client/auth/useSignIn.d.ts +1 -1
- package/dist/client/auth/useSignOut.d.ts +1 -1
- package/dist/client/auth/useSignUp.d.ts +1 -1
- package/dist/client/index.d.ts +4 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +136 -9
- package/dist/client/index.js.map +1 -1
- package/dist/client/realtime/RealtimeClient.d.ts +8 -1
- package/dist/client/realtime/RealtimeClient.d.ts.map +1 -1
- package/dist/client/useMutation.d.ts +18 -8
- package/dist/client/useMutation.d.ts.map +1 -1
- package/dist/client/useSetQueryData.d.ts +69 -0
- package/dist/client/useSetQueryData.d.ts.map +1 -0
- package/dist/config/index.js +1 -1
- package/dist/console/run.js +2 -2
- package/dist/console/run.js.map +1 -1
- package/dist/container/index.js +2 -2
- package/dist/container/index.js.map +1 -1
- package/dist/database/index.js +2 -2
- package/dist/database/index.js.map +1 -1
- package/dist/email/index.js +2 -2
- package/dist/email/index.js.map +1 -1
- package/dist/facades/Auth.d.ts +29 -2
- package/dist/facades/Auth.d.ts.map +1 -1
- package/dist/facades/RateLimiter.d.ts +16 -1
- package/dist/facades/RateLimiter.d.ts.map +1 -1
- package/dist/facades/index.js +2 -2
- package/dist/facades/index.js.map +1 -1
- package/dist/foundation/index.js +2 -2
- package/dist/foundation/index.js.map +1 -1
- package/dist/http/HttpRequest.d.ts +14 -0
- package/dist/http/HttpRequest.d.ts.map +1 -1
- package/dist/http/McpRouter.d.ts +121 -2
- package/dist/http/McpRouter.d.ts.map +1 -1
- package/dist/http/RateLimitExceededError.d.ts +24 -0
- package/dist/http/RateLimitExceededError.d.ts.map +1 -0
- package/dist/http/RateLimitMiddleware.d.ts +2 -5
- package/dist/http/RateLimitMiddleware.d.ts.map +1 -1
- package/dist/http/index.d.ts +2 -1
- package/dist/http/index.d.ts.map +1 -1
- package/dist/http/index.js +2 -2
- package/dist/http/index.js.map +1 -1
- package/dist/http/refusal.d.ts +6 -1
- package/dist/http/refusal.d.ts.map +1 -1
- package/dist/http/requestContext.d.ts +3 -1
- package/dist/http/requestContext.d.ts.map +1 -1
- package/dist/http/requestState.d.ts +57 -0
- package/dist/http/requestState.d.ts.map +1 -0
- package/dist/i18n/dictionaryRuntime.js +2 -2
- package/dist/i18n/dictionaryRuntime.js.map +1 -1
- package/dist/i18n/index.js +2 -2
- package/dist/i18n/index.js.map +2 -2
- package/dist/kernel/index.js +2 -2
- package/dist/kernel/index.js.map +2 -2
- package/dist/orm/index.js +2 -2
- package/dist/orm/index.js.map +1 -1
- package/dist/server/Server.d.ts.map +1 -1
- package/dist/server/health.d.ts +67 -0
- package/dist/server/health.d.ts.map +1 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -2
- package/dist/server/index.js.map +5 -4
- package/dist/server/shutdown.d.ts +3 -4
- package/dist/server/shutdown.d.ts.map +1 -1
- package/dist/services/broadcast/BroadcastDriver.d.ts +3 -1
- package/dist/services/broadcast/BroadcastDriver.d.ts.map +1 -1
- package/dist/services/broadcast/BroadcastManager.d.ts.map +1 -1
- package/dist/services/broadcast/BroadcastServiceProvider.d.ts +10 -0
- package/dist/services/broadcast/BroadcastServiceProvider.d.ts.map +1 -1
- package/dist/services/broadcast/RedisBroadcastDriver.d.ts +155 -0
- package/dist/services/broadcast/RedisBroadcastDriver.d.ts.map +1 -0
- package/dist/services/broadcast/SocketHub.d.ts +9 -0
- package/dist/services/broadcast/SocketHub.d.ts.map +1 -1
- package/dist/services/broadcast/config.d.ts +16 -3
- package/dist/services/broadcast/config.d.ts.map +1 -1
- package/dist/services/broadcast/workerWarning.d.ts +10 -0
- package/dist/services/broadcast/workerWarning.d.ts.map +1 -0
- package/dist/services/features/gate.d.ts +11 -0
- package/dist/services/features/gate.d.ts.map +1 -0
- package/dist/services/index.d.ts +6 -5
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +3 -3
- package/dist/services/index.js.map +2 -2
- package/dist/services/logging/LogManager.d.ts +1 -0
- package/dist/services/logging/LogManager.d.ts.map +1 -1
- package/dist/services/logging/config.d.ts +23 -1
- package/dist/services/logging/config.d.ts.map +1 -1
- package/dist/services/logging/consoleSink.d.ts +25 -0
- package/dist/services/logging/consoleSink.d.ts.map +1 -0
- package/dist/services/mcp/McpRegistry.d.ts +106 -14
- package/dist/services/mcp/McpRegistry.d.ts.map +1 -1
- package/dist/services/mcp/http/McpHttpServer.d.ts +41 -2
- package/dist/services/mcp/http/McpHttpServer.d.ts.map +1 -1
- package/dist/services/mcp/toAgentTools.d.ts +21 -3
- package/dist/services/mcp/toAgentTools.d.ts.map +1 -1
- package/dist/services/queue/WorkerProcess.d.ts.map +1 -1
- package/dist/services/queue/work.js +2 -2
- package/dist/services/queue/work.js.map +5 -4
- package/dist/services/rate-limiter/RateLimiter.d.ts +12 -0
- package/dist/services/rate-limiter/RateLimiter.d.ts.map +1 -1
- package/dist/services/router/globalMiddleware.d.ts +4 -3
- package/dist/services/router/globalMiddleware.d.ts.map +1 -1
- package/dist/stats/route-table.js +1 -1
- package/dist/support/index.js +2 -2
- package/dist/support/index.js.map +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/vitest/index.js +1 -1
- package/package.json +1 -1
- package/skills/gemi-react-best-practices/SKILL.md +1 -1
- package/skills/gemi-react-best-practices/rules/query-mutate-over-refetch.md +14 -0
- package/skills/gemi-react-best-practices/rules/routing-middleware-dsl.md +2 -1
- package/dist/chunk-39dx7xrz.js +0 -10
- package/dist/chunk-39dx7xrz.js.map +0 -43
- package/dist/chunk-d0wr9jk4.js +0 -5
- package/dist/chunk-d0wr9jk4.js.map +0 -12
- package/dist/chunk-eevna943.js.map +0 -10
- package/dist/chunk-gvp6brdt.js +0 -57
- package/dist/chunk-kc924zjz.js +0 -5
- package/dist/chunk-kc924zjz.js.map +0 -12
- package/dist/chunk-tazvfppr.js +0 -5
- package/dist/chunk-vpgbn494.js +0 -24
- package/dist/chunk-z23h4s1a.js +0 -14
- package/dist/chunks/ThemeProvider-CgK2mmVV.js.map +0 -1
- /package/dist/{chunk-j0cnsgjq.js.map → chunk-6q6bhkyf.js.map} +0 -0
- /package/dist/{chunk-4qpypa3h.js.map → chunk-ayfjjgv2.js.map} +0 -0
- /package/dist/{chunk-rjm1kj8n.js.map → chunk-gp00enrk.js.map} +0 -0
- /package/dist/{chunk-xhmtph39.js.map → chunk-j10a0m7q.js.map} +0 -0
- /package/dist/{chunk-wqharhrp.js.map → chunk-j12hpdxk.js.map} +0 -0
- /package/dist/{chunk-8x73yyfs.js.map → chunk-s4semb89.js.map} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{
|
|
2
|
+
import{aj as k,cj as T0}from"./chunk-rany5zgk.js";import{dj as S0}from"./chunk-sv125fqq.js";import{fj as N0,gj as R0,hj as Q0,jj as C,lj as q,uj as B0}from"./chunk-vhvvjaj3.js";import{Jj as X0}from"./chunk-npbf06c1.js";import{ek as W0,hk as b}from"./chunk-6gwxvmjv.js";import{qk as M0}from"./chunk-z5nfve1k.js";class y{table;sql;dialect;connection;busyTimeout;configured;constructor(z,V={}){let Y=V.table??"gemi_locks";if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(Y))throw Error(`The lock table name "${Y}" is not a plain identifier. Use letters, digits and underscores.`);this.table=Y,this.sql=z.sql,this.dialect=z.dialect,this.connection=z.name,this.busyTimeout=V.busyTimeout??1000}async createTable(){await this.configure();for(let z of v0(this.dialect,this.table))await this.sql.unsafe(z)}async acquire(z,V,Y){await this.configure();let Z=this.sql,$=this.now(Z);if(await this.seed(Z,z),this.mysql){let H=await Z`
|
|
3
3
|
UPDATE ${this.name(Z)}
|
|
4
4
|
SET owner = ${V}, token = token + 1, expires_at = ${$} + ${this.ms(Z,Y)},
|
|
5
5
|
updated_at = ${$}
|
|
@@ -74,7 +74,7 @@ import{gi as k,ii as T0}from"./chunk-1f1sb3w7.js";import{ji as S0}from"./chunk-7
|
|
|
74
74
|
"token" BIGINT NOT NULL DEFAULT 0,
|
|
75
75
|
"expires_at" BIGINT NOT NULL,
|
|
76
76
|
"updated_at" BIGINT NOT NULL${Z}
|
|
77
|
-
)`]}var I="gemi.WorkflowTick",t=262144;function w(z,V){let Y=(Z)=>Z.slice(0,Z.lastIndexOf(":"));return Y(z)===Y(V)}class R extends Error{constructor(z){super(`The tick running workflow ${z} lost its hold on it (another tick took it over after its lease ran out), so its writes were refused.`);this.name="WorkflowLeaseLostError"}}var j0=["completed","failed","cancelled"];class o{db;table;stepTable;constructor(z,V){this.db=z;this.table=V.table,this.stepTable=V.stepTable}joinsTransaction(){return this.db.transaction()!==void 0}create(z){let V=this.db.transaction(),Y=V?this.insertWorkflow(V,z):this.db.atomically((Z)=>this.insertWorkflow(Z,z));if(V)q(Y);return Y}async insertWorkflow(z,V){await this.db.configure();let Y=this.db.now(z);await T(z`
|
|
77
|
+
)`]}class p{entries=new Map;counters=new Map;async acquire(z,V,Y){let Z=Date.now(),$=this.entries.get(z);if($&&($.expiresAt>Z||$.fences>0))return null;let X=($?.token??0)+1;return this.entries.set(z,{owner:V,token:X,expiresAt:Z+Math.max(0,Y),fences:0}),X}async extend(z,V,Y,Z){let $=this.current(z,V,Y);if(!$)return!1;return $.expiresAt=Date.now()+Math.max(0,Z),!0}async release(z,V,Y){let Z=this.current(z,V,Y);if(!Z)return!1;return Z.owner="",Z.expiresAt=0,!0}async holder(z){let V=this.entries.get(z);if(!V||V.expiresAt<=Date.now())return null;return{owner:V.owner,token:V.token}}async held(z,V,Y){return this.current(z,V,Y)!==void 0}async advance(z,V){if((this.counters.get(z)??-1/0)>=V)return!1;return this.counters.set(z,V),!0}async fence(z,V,Y,Z){let $=this.current(z,V,Y);if(!$)throw new k(z,Y);$.fences++;try{return await Z()}finally{$.fences--}}windows=new Map;async hit(z,V,Y){let Z=Date.now(),$=this.windows.get(z);if(!$||$.endsAt<=Z)$={count:0,endsAt:Z+Math.max(1,Y)},this.windows.set(z,$);if($.count>=V)return{allowed:!1,resetInMs:$.endsAt-Z};return $.count++,{allowed:!0,resetInMs:$.endsAt-Z}}async refund(z){let V=this.windows.get(z);if(V&&V.endsAt>Date.now()&&V.count>0)V.count--}current(z,V,Y){let Z=this.entries.get(z);if(!Z||Z.owner!==V||Z.expiresAt<=Date.now())return;if(Y!==void 0&&Z.token!==Y)return;return Z}}var I="gemi.WorkflowTick",t=262144;function w(z,V){let Y=(Z)=>Z.slice(0,Z.lastIndexOf(":"));return Y(z)===Y(V)}class R extends Error{constructor(z){super(`The tick running workflow ${z} lost its hold on it (another tick took it over after its lease ran out), so its writes were refused.`);this.name="WorkflowLeaseLostError"}}var j0=["completed","failed","cancelled"];class o{db;table;stepTable;constructor(z,V){this.db=z;this.table=V.table,this.stepTable=V.stepTable}joinsTransaction(){return this.db.transaction()!==void 0}create(z){let V=this.db.transaction(),Y=V?this.insertWorkflow(V,z):this.db.atomically((Z)=>this.insertWorkflow(Z,z));if(V)q(Y);return Y}async insertWorkflow(z,V){await this.db.configure();let Y=this.db.now(z);await T(z`
|
|
78
78
|
INSERT INTO ${this.workflows(z)}
|
|
79
79
|
(id, name, args, status, progress, retick, created_at, updated_at)
|
|
80
80
|
VALUES
|
|
@@ -392,7 +392,7 @@ ADD COLUMN IF NOT EXISTS "progress" ${Y}`,`CREATE INDEX IF NOT EXISTS "${V}_batc
|
|
|
392
392
|
"finished_at" BIGINT,
|
|
393
393
|
"created_at" BIGINT NOT NULL,
|
|
394
394
|
"updated_at" BIGINT NOT NULL${Z}
|
|
395
|
-
)`]}function A0(z){let V=JSON.parse(z.options),Y=(Z)=>Z==null?null:Number(Z);return{id:String(z.id),name:z.name==null?null:String(z.name),total:Number(z.total),pending:Number(z.pending),succeeded:Number(z.succeeded),failed:Number(z.failed),cancelled:Number(z.cancelled),failedJobIds:JSON.parse(z.failed_job_ids),cancelledAt:Y(z.cancelled_at),finishedAt:Y(z.finished_at),createdAt:Number(z.created_at),allowFailures:V.allowFailures===!0,callbacks:V.callbacks??{}}}function m0(z){return JSON.stringify({allowFailures:z.allowFailures,callbacks:z.callbacks})}function _0(z){let V=String(z?.message??z);return/does not exist|doesn't exist|unknown column|no such (table|column)|has no column/i.test(V)}async function e(z,V){try{return await z}catch(Y){if(!_0(Y))throw Y;throw Error(`Job batches need the "${V}" table and the batch_id and progress columns of the jobs table, and the database says one is missing. Add the GemiJobBatch model and the two GemiJob fields from the docs (docs/jobs-and-queues.md#batches) and migrate, or call the driver's createTable().`,{cause:Y})}}import{AsyncResource as c0}from"async_hooks";import{isMainThread as l0}from"worker_threads";function Nz(z){return z}function C0(){return{jobs:[],jobsDir:"app/jobs",workflows:[],workflowsDir:"app/workflows",concurrency:1,driver:"memory",visibilityTimeout:300000,pollInterval:1000,unknownJobGrace:3600000,locks:"auto"}}var b0=86400000;class V0{queue;workflows=new Map;steps=new Map;constructor(z){this.queue=z}async create(z){if(this.workflows.has(z.id))throw Error(`A workflow with the id ${z.id} already exists.`);this.prune(b0);let V=Date.now();this.workflows.set(z.id,{...z,status:"running",currentStep:null,progress:0,result:null,error:null,wakeAt:null,lockedBy:null,lockedUntil:null,retick:!1,createdAt:V,updatedAt:V}),this.steps.set(z.id,new Map),this.tick(z.id,0)}async find(z,V={}){let Y=this.workflows.get(z);if(!Y)return null;return{workflow:{...Y},steps:V.steps===!1?[]:this.stepsOf(z)}}async acquire(z,V,Y){let Z=this.workflows.get(z);if(!Z)return{kind:"missing"};let $=Date.now();if(Z.lockedBy!==null&&!w(Z.lockedBy,V)&&(Z.lockedUntil??0)>$)return Z.retick=!0,{kind:"busy"};return Z.lockedBy=V,Z.lockedUntil=$+Y,Z.retick=!1,{kind:"acquired",workflow:{...Z},steps:this.stepsOf(z)}}async renew(z,V,Y){let Z=this.workflows.get(z);if(!Z||Z.lockedBy!==V)return!1;return Z.lockedUntil=Date.now()+Y,!0}async update(z,V,Y){let Z=this.workflows.get(z);if(!Z)return;if(V.owner!==void 0&&Z.lockedBy!==V.owner)throw new R(z);let $=this.steps.get(z),X=V.key===void 0?void 0:$.get(V.key),H=Date.now(),G=Y({workflow:{...Z},step:X?{...X}:null,steps:V.allSteps?this.stepsOf(z):[],now:H});if(G.step){let Q=$.get(G.step.key);$.set(G.step.key,{...G.step,createdAt:Q?.createdAt??H,updatedAt:H})}if(G.batch)this.queue.enqueueBatch(G.batch);for(let Q of G.cancelBatches??[])this.queue.cancelBatch(Q);if(G.workflow)Object.assign(Z,G.workflow);if(Z.updatedAt=H,G.tick)this.tick(z,G.tick.delayMs);if(G.unlock){if(Z.lockedBy=null,Z.lockedUntil=null,Z.retick)Z.retick=!1,this.tick(z,0)}return G.result}async prune(z){let V=Date.now()-z,Y=0;for(let[Z,$]of this.workflows)if(["completed","failed","cancelled"].includes($.status)&&$.updatedAt<=V)this.workflows.delete(Z),this.steps.delete(Z),Y++;return Y}stepsOf(z){return[...this.steps.get(z)?.values()??[]].map((V)=>({...V}))}tick(z,V){this.queue.enqueue({name:I,args:JSON.stringify([z]),delayMs:Math.max(0,Math.round(V))})}}var u0=86400000;class i{entries=new Map;batches=new Map;workflows;listeners=new Set;timer;timerAt=1/0;seq=0;get waiting(){let z=0;for(let V of this.entries.values())if(!V.leased)z++;return z}get leased(){return this.entries.size-this.waiting}async enqueue(z){let V=this.add(z);return this.changed(),V}add({name:z,args:V,delayMs:Y=0,id:Z=crypto.randomUUID()},$){let X=Date.now();return this.entries.set(Z,{job:{id:Z,name:z,args:V,attempt:0,createdAt:X,...$===void 0?{}:{batchId:$}},until:X+Math.max(0,Y),leased:!1,seq:this.seq++,progress:0}),Z}async enqueueBatch(z){this.recordBatch(z)}recordBatch(z){let V=Date.now();this.forgetFinishedBatches(V);let Y=d({...z,total:z.args.length,now:V});for(let X of z.args)this.add({name:z.job,args:X},z.id);let{record:Z,calls:$}=x(Y,Y,V);this.batches.set(z.id,Z);for(let X of $)this.add(X);this.changed()}async findBatch(z,V={}){let Y=this.batches.get(z);if(!Y)return null;if(V.progress===!1||Y.pending===0)return W(Y);let Z=0;for(let $ of this.entries.values())if($.job.batchId===z)Z+=$.progress;return W(Y,Z)}async cancelBatch(z){return this.cancelBatchNow(z)}cancelBatchNow(z){let V=this.batches.get(z);if(!V||V.finishedAt!==null||V.cancelledAt!==null)return!1;let Y=Date.now(),Z=M(V,Y,this.cancelWaiting(z));return this.save(V,Z,Y),this.changed(),!0}workflowStore(){return this.workflows??=new V0({enqueue:(z)=>{this.add(z),this.changed()},enqueueBatch:(z)=>this.recordBatch(z),cancelBatch:(z)=>void this.cancelBatchNow(z)}),this.workflows}async reportProgress(z,V){let Y=this.current(z);if(Y)Y.progress=E(V)}async claim(z,V){let Y=Date.now(),Z=[...this.entries.values()].filter(($)=>$.until<=Y).sort(($,X)=>$.until-X.until||$.seq-X.seq).slice(0,Math.max(0,z));for(let $ of Z)$.job={...$.job,attempt:$.job.attempt+1},$.leased=!0,$.until=Y+V.visibilityTimeoutMs;if(Z.length>0)this.schedule();return Z.map(($)=>({...$.job}))}async complete(z){let V=this.current(z);if(!V)return;this.entries.delete(z.id),this.count(V,"succeeded"),this.schedule()}async fail(z,V){let Y=this.current(z);if(!Y)return;let Z=Y.job.batchId===void 0?void 0:this.batches.get(Y.job.batchId),$=V.cancelled===!0||V.retryInMs!==null&&Z?.cancelledAt!=null;if(V.retryInMs===null||$){this.entries.delete(z.id),this.count(Y,$?"cancelled":"failed"),this.schedule();return}Y.leased=!1,Y.until=Date.now()+Math.max(0,V.retryInMs),Y.seq=this.seq++,Y.progress=0,this.changed()}async release(z,V){let Y=this.current(z);if(!Y)return;Y.job={...Y.job,attempt:Y.job.attempt-1},Y.leased=!1,Y.until=Date.now()+Math.max(0,V.retryInMs),Y.seq=this.seq++,this.changed()}async heartbeat(z,V){let Y=Date.now()+V.visibilityTimeoutMs;for(let Z of z){let $=this.current(Z);if($)$.until=Y}this.schedule()}count(z,V){let Y=z.job.batchId;if(Y===void 0)return;let Z=this.batches.get(Y);if(!Z)return;let $=Date.now(),X=c(Z,V,z.job.id);if(l(Z,X))X=M(X,$,this.cancelWaiting(Y));this.save(Z,X,$),this.changed()}save(z,V,Y){let{record:Z,calls:$}=x(z,V,Y);this.batches.set(Z.id,Z);for(let X of $)this.add(X)}cancelWaiting(z){let V=0;for(let[Y,Z]of this.entries)if(Z.job.batchId===z&&!Z.leased)this.entries.delete(Y),V++;return V}forgetFinishedBatches(z){for(let[V,Y]of this.batches)if(Y.finishedAt!==null&&z-Y.finishedAt>u0)this.batches.delete(V)}subscribe(z){return this.listeners.add(z),()=>void this.listeners.delete(z)}current(z){let V=this.entries.get(z.id);if(!V||!V.leased||V.job.attempt!==z.attempt)return;return V}changed(){this.schedule();let z=Date.now();for(let V of this.entries.values())if(V.until<=z){this.wake();return}}wake(){for(let z of[...this.listeners])z()}schedule(){let z=Date.now(),V=1/0;for(let Y of this.entries.values())if(Y.until>z&&Y.until<V)V=Y.until;if(V===this.timerAt)return;if(clearTimeout(this.timer),this.timer=void 0,this.timerAt=V,V===1/0)return;this.timer=setTimeout(()=>{this.timer=void 0,this.timerAt=1/0,this.changed()},V-z),this.timer.unref?.()}}function s(z,V){let Y=Array.isArray(z)?z[Math.min(V,z.length)-1]:z;return Math.max(0,Y??0)}var k0={ms:1,s:1000,m:60000,h:3600000,d:86400000,w:604800000};function n(z){if(typeof z==="number"){if(!Number.isFinite(z)||z<0)throw TypeError(`A duration is 0 or more milliseconds; got ${z}.`);return Math.round(z)}let V=/^\s*(\d+(?:\.\d+)?)\s*(ms|s|m|h|d|w)\s*$/.exec(String(z));if(!V)throw TypeError(`"${String(z)}" is not a duration. Use milliseconds, or a number and one of ms, s, m, h, d, w ("30s", "7d").`);return Math.round(Number(V[1])*k0[V[2]])}class I0 extends Error{step;batch;constructor(z,V,Y){super(V);this.step=z;this.batch=Y;this.name="StepFailedError"}}class Y0 extends Error{step;constructor(z){super(`No signal "${z}" arrived before its timeout.`);this.step=z;this.name="WaitTimeoutError"}}class E0 extends Error{constructor(z,V){super(`Step "${z}" took longer than its timeout of ${V}ms.`);this.name="StepTimeoutError"}}class O0 extends Error{constructor(z){super(`Workflow ${z} was cancelled.`);this.name="WorkflowCancelledError"}}class g extends Error{constructor(){super("The workflow is suspended until a step can continue. Rethrow this error if you catch it.");this.name="WorkflowSuspended"}}var D0=Symbol("done");class Z0{tick;workflowId;steps;seen=new Set;pending=new Set;suspension;lost=!1;cancelled=!1;current=null;constructor(z){this.tick=z;this.workflowId=z.workflowId,this.steps=new Map(z.steps.map((V)=>[V.key,V]))}run(z,V,Y={}){return this.track(z,()=>this.runStep(z,V,Y))}sleep(z,V){let Y=n(V);return this.track(z,()=>this.sleepStep(z,Y))}waitFor(z,V={}){let Y=V.timeout===void 0?void 0:n(V.timeout);return this.track(z,()=>this.waitStep(z,Y))}batch(z,V,Y,Z={}){return this.track(z,()=>this.batchStep(z,V,Y,Z))}async progress(z){let V=E(z);this.assertRunning();let Y=this.write(void 0,()=>({result:void 0,workflow:{progress:V}}));this.remember(Y),await Y}async settled(){while(this.pending.size>0)await Promise.allSettled(this.pending)}track(z,V){if(typeof z!=="string"||z.length===0||z.length>191)throw TypeError(`A step key is a string of 1 to 191 characters; got ${JSON.stringify(z)}.`);if(this.seen.has(z))throw Error(`Two steps of workflow ${this.workflowId} use the key "${z}". Each step needs a key of its own, or the second would return the first one's result.`);this.seen.add(z),this.assertRunning();let Y=V();return this.remember(Y),Y}remember(z){this.pending.add(z);let V=()=>void this.pending.delete(z);z.then(V,V)}assertRunning(){if(this.lost)throw new R(this.workflowId);if(this.suspension)throw new g}suspend(z,V){if(!this.suspension)this.suspension={status:z,wakes:[]};if(V!=null)this.suspension.wakes.push(V);throw new g}async write(z,V){let Y;try{Y=await this.tick.store.update(this.tick.workflowId,{owner:this.tick.owner,...z===void 0?{}:{key:z}},(Z)=>{if(Z.workflow.status==="cancelling"&&!this.tick.cancelling)return{result:D0};let $=V(Z);return{...$,result:{value:$.result}}})}catch(Z){if(Z instanceof R)this.lost=!0;throw Z}if(Y===void 0)throw this.lost=!0,new R(this.tick.workflowId);if(Y===D0)this.cancelled=!0,this.suspend("waiting");return Y.value}record(z,V,Y){let Z={workflowId:this.tick.workflowId,key:z,status:"running",attempt:0,output:null,error:null,batchId:null,wakeAt:null,startedAt:null,finishedAt:null,createdAt:0,updatedAt:0,...V,...Y};return this.steps.set(z,Z),Z}mismatch(z,V,Y){throw Error(`Step "${z}" of workflow ${this.tick.workflowId} was recorded as a ${V} step, and is now used as ${Y}. A key belongs to one step; rename one of them.`)}async runStep(z,V,Y){let Z=Math.max(1,Math.floor(Y.attempts??3)),$=Y.timeout===void 0?void 0:n(Y.timeout),X=this.steps.get(z);if(X?.status==="completed")return _(X.output);if(X?.status==="failed")throw j(z,X);if(X?.status==="retrying"&&X.wakeAt!==null&&X.wakeAt>Date.now())this.current=z,this.suspend("sleeping",X.wakeAt);for(;;){let H=await this.write(z,({workflow:J,step:P,now:N})=>{if(P?.status==="completed")return{result:{kind:"done",output:P.output}};if(P?.status==="failed")return{result:{kind:"failed",step:P}};if(P&&P.status!=="running"&&P.status!=="retrying")this.mismatch(z,P.status,"step.run");if(P?.status==="retrying"&&P.wakeAt!==null&&P.wakeAt>N)return{result:{kind:"wait",wakeAt:P.wakeAt}};let D=(P?.attempt??0)+1;if(D>Z){let G0=this.record(z,P,{status:"failed",error:`Attempt ${D-1} of ${Z} never finished, most likely because the process running it exited.`+(P?.error?` The last error was: ${P.error}`:""),finishedAt:N,wakeAt:null});return{result:{kind:"failed",step:G0},step:G0}}let u=this.record(z,P,{status:"running",attempt:D,startedAt:N,finishedAt:null,wakeAt:null});return{result:{kind:"run",attempt:D},step:u,workflow:J.status==="cancelling"?{currentStep:z}:{currentStep:z,status:"running"}}});if(this.current=z,H.kind==="done")return _(H.output);if(H.kind==="failed")throw j(z,H.step);if(H.kind==="wait")this.suspend("sleeping",H.wakeAt);let G=H.attempt,Q,B,K=!0;try{Q=await this.execute(z,V,G,$)}catch(J){B=J}if(this.cancelled)throw new g;let A=null;if(B===void 0)try{A=m(Q,`The result of step "${z}"`)}catch(J){B=J,K=!1}if(B===void 0)return await this.write(z,({step:J,now:P})=>({result:void 0,step:this.record(z,J,{status:"completed",output:A,error:null,wakeAt:null,finishedAt:P})})),_(A);let F=a(B);if(K&&G<Z){let J=s(Y.backoff??0,G),P=await this.write(z,({step:N,now:D})=>{let u=J>0?D+J:null;return{result:u,step:this.record(z,N,{status:"retrying",error:F,wakeAt:u})}});if(P!==null)this.suspend("sleeping",P);continue}let U=await this.write(z,({step:J,now:P})=>{let N=this.record(z,J,{status:"failed",error:F,wakeAt:null,finishedAt:P});return{result:N,step:N}});throw j(z,U)}}async execute(z,V,Y,Z){let $=new AbortController,X={idempotencyKey:`${this.tick.workflowId}:${z}`,attempt:Y,signal:$.signal},H=Promise.resolve().then(()=>V(X)),G,Q,B=new Promise((K,A)=>{let F=(U)=>{$.abort(U),A(U)};if(Z!==void 0)G=setTimeout(()=>F(new E0(z,Z)),Z);if(!this.tick.cancelling)Q=setInterval(()=>{this.tick.store.find(this.tick.workflowId,{steps:!1}).then((U)=>{if(U?.workflow.status!=="cancelling"||$.signal.aborted)return;if(this.cancelled=!0,!this.suspension)this.suspension={status:"waiting",wakes:[]};F(new O0(this.tick.workflowId))}).catch(()=>{})},this.tick.cancelCheckMs),Q.unref?.()});try{return await Promise.race([H,B])}finally{clearTimeout(G),clearInterval(Q),H.catch(()=>{}),B.catch(()=>{})}}async sleepStep(z,V){let Y=this.steps.get(z);if(Y?.status==="completed")return;if(this.current=z,Y?.status==="sleeping"&&Y.wakeAt!==null&&Y.wakeAt>Date.now())this.suspend("sleeping",Y.wakeAt);let Z=await this.write(z,({step:$,now:X})=>{if($?.status==="completed")return{result:null};if($&&$.status!=="sleeping")this.mismatch(z,$.status,"step.sleep");let H=$?.wakeAt??X+V;if(H<=X)return{result:null,step:this.record(z,$,{status:"completed",wakeAt:H,startedAt:$?.startedAt??X,finishedAt:X})};if($)return{result:H};return{result:H,step:this.record(z,null,{status:"sleeping",wakeAt:H,startedAt:X}),workflow:{currentStep:z}}});if(Z!==null)this.suspend("sleeping",Z)}async waitStep(z,V){let Y=this.steps.get(z);if(Y?.status==="completed")return _(Y.output);if(Y?.status==="timed_out")throw new Y0(z);if(this.current=z,Y?.status==="waiting"&&(Y.wakeAt===null||Y.wakeAt>Date.now()))this.suspend("waiting",Y.wakeAt);let Z=await this.write(z,({step:$,now:X})=>{if($?.status==="completed")return{result:{kind:"value",output:$.output}};if($?.status==="timed_out")return{result:{kind:"timeout"}};if($?.status==="signalled")return{result:{kind:"value",output:$.output},step:this.record(z,$,{status:"completed",wakeAt:null,startedAt:$.startedAt??X,finishedAt:X})};if($&&$.status!=="waiting")this.mismatch(z,$.status,"step.waitFor");if($){if($.wakeAt!==null&&$.wakeAt<=X)return{result:{kind:"timeout"},step:this.record(z,$,{status:"timed_out",finishedAt:X})};return{result:{kind:"wait",wakeAt:$.wakeAt}}}let H=V===void 0?null:X+V;return{result:{kind:"wait",wakeAt:H},step:this.record(z,null,{status:"waiting",wakeAt:H,startedAt:X}),workflow:{currentStep:z}}});if(Z.kind==="value")return _(Z.output);if(Z.kind==="timeout")throw new Y0(z);this.suspend("waiting",Z.wakeAt)}async batchStep(z,V,Y,Z){let $=Z.allowFailures===!0,X=this.steps.get(z);if(X?.status==="completed")return _(X.output);if(X?.status==="failed")throw j(z,X);if(X&&X.status!=="batching")this.mismatch(z,X.status,"step.batch");if(this.current=z,!X){let A=this.tick.buildBatch(V,Y,{name:Z.name??`workflow:${this.tick.workflowId}:${z}`,allowFailures:$});if(X=await this.write(z,({step:F,now:U})=>{if(F)return{result:F};let J=this.record(z,null,{status:"batching",batchId:A.id,startedAt:U});return{result:J,step:J,batch:A,workflow:{currentStep:z}}}),this.tick.scheduled(),X.status==="completed")return _(X.output);if(X.status==="failed")throw j(z,X)}let H=X.batchId===null?null:await this.tick.findBatch(X.batchId);if(H&&H.finishedAt===null)this.suspend("waiting");let G=H!==null&&H.cancelledAt===null&&(H.failed===0||$),Q=H===null?null:JSON.stringify(H),B=G?null:H===null?`The batch of step "${z}" (${X.batchId}) no longer exists.`:`The batch of step "${z}" failed: ${H.failed} failed and ${H.cancelled} cancelled of ${H.total}.`,K=await this.write(z,({step:A,now:F})=>{let U=this.record(z,A,{status:G?"completed":"failed",output:Q,error:B,finishedAt:F});return{result:U,step:U}});if(!G)throw j(z,K);return H}}function j(z,V){let Y=V.batchId!==null&&V.output!==null?JSON.parse(V.output):void 0;return new I0(z,Y?V.error??`Step "${z}" failed.`:`Step "${z}" failed: ${V.error??"unknown error"}`,Y)}function m(z,V){if(z===void 0)return null;let Y=JSON.stringify(z);if(Y===void 0)throw TypeError(`${V} cannot be stored: JSON has no form for it.`);let Z=Buffer.byteLength(Y,"utf8");if(Z>t)throw RangeError(`${V} is ${Z} bytes as JSON, over the ${t}-byte limit. Store it elsewhere and return its id.`);return Y}function _(z){return z===null?void 0:JSON.parse(z)}function a(z){return z instanceof Error?z.message:String(z)}var r=["completed","failed","cancelled"],p0=1000;class $0{queue;registry={};storeInstance;tickClass;reportedNames=new Set;constructor(z){this.queue=z}get workflows(){return this.registry}use(z){this.registry={};for(let V of z){if(V.name==="unset"||!V.name){console.error("A workflow class has no `static name`, so it was not registered. Add one.");continue}if(this.registry[V.name]){console.error(`Two workflows are named "${V.name}" \u2014 the first is registered `+"and this one is not. A workflow's name is its key in storage. Rename one.");continue}this.registry[V.name]=V}}get tickJob(){return this.tickClass??=w0(this),this.tickClass}get store(){if(!this.storeInstance){let z=this.queue.driver.workflowStore?.();if(!z||!this.queue.driver.enqueueBatch)throw Error("This queue's driver does not support workflows. The memory and database drivers do.");this.storeInstance=z}return this.storeInstance}start(z,V){if(z.name==="unset"||!z.name)throw Error("Cannot start a workflow with no name");let Y=this.store,Z={id:Bun.randomUUIDv7(),name:z.name,args:m(V,`The arguments of ${z.name}`)??"[]"},$=()=>this.queue.claimSoon(),X=Y.joinsTransaction?.()===!0;if(!X){if(C(()=>Y.create(Z).then($,(B)=>{console.error(`[gemi] The queue could not record the workflow ${z.name}, which was held until its transaction committed. The transaction stays committed; the workflow did not start.`,B)})))return Promise.resolve(Z.id)}let H=Y.create(Z),G=X&&C($);return H.then(()=>{if(!G)$();return Z.id})}async signal(z,V,Y){if(typeof V!=="string"||V.length===0||V.length>191)throw TypeError("A signal key is a string of 1 to 191 characters.");let Z=m(Y,`The payload of signal "${V}"`),$=await this.store.update(z,{key:V},({workflow:X,step:H,now:G})=>{if(r.includes(X.status)||X.status==="cancelling")return{result:!1};if(!H)return{result:!0,step:{workflowId:z,key:V,status:"signalled",attempt:0,output:Z,error:null,batchId:null,wakeAt:null,startedAt:null,finishedAt:G,createdAt:G,updatedAt:G}};if(H.status!=="waiting")return{result:!1};return{result:!0,step:{...H,status:"signalled",output:Z,wakeAt:H.wakeAt,finishedAt:G},tick:{delayMs:0}}});if($)this.queue.claimSoon();return $===!0}async cancel(z){let V=await this.store.update(z,{allSteps:!0},({workflow:Y,steps:Z})=>{if(r.includes(Y.status)||Y.status==="cancelling")return{result:!1};return{result:!0,workflow:{status:"cancelling"},cancelBatches:Z.filter(($)=>$.status==="batching"&&$.batchId!==null).map(($)=>$.batchId),tick:{delayMs:0}}});if(V)this.queue.claimSoon();return V===!0}async find(z){let V=await this.store.find(z);if(!V)return null;let{workflow:Y,steps:Z}=V,$=[];try{$=JSON.parse(Y.args)}catch{}return{id:Y.id,name:Y.name,status:Y.status,args:$,currentStep:Y.currentStep,progress:Y.progress,result:d0(Y.result),error:Y.error,steps:await Promise.all(Z.map(async(X)=>{let H={key:X.key,status:X.status,attempt:X.attempt,error:X.error,batchId:X.batchId,wakeAt:X.wakeAt,startedAt:X.startedAt,finishedAt:X.finishedAt};if(X.batchId===null)return H;let G=await this.queue.driver.findBatch?.(X.batchId);return G?{...H,progress:G.progress}:H})),createdAt:Y.createdAt,updatedAt:Y.updatedAt}}async tick(z,V){let Y=this.store,Z=V.$claimed,$=Z?`${Z.id}:${Z.attempt}`:`${crypto.randomUUID()}:1`,X=Math.max(1,this.queue.config.visibilityTimeout),H=await Y.acquire(z,$,X);if(H.kind!=="acquired")return;let{workflow:G}=H,Q=(J={})=>Y.update(z,{owner:$},()=>({...J,result:void 0,unlock:!0})).then(()=>this.queue.claimSoon()).catch((P)=>{if(!(P instanceof R))throw P});if(r.includes(G.status))return Q();let B=this.registry[G.name];if(!B)return this.unknown(G,V,Q);let K;try{K=JSON.parse(G.args)}catch(J){return Q({workflow:{status:"failed",error:`The arguments are not JSON: ${a(J)}`}})}let A=setInterval(()=>{Y.renew(z,$,X).catch((J)=>{console.error(`[gemi] Could not extend the hold on workflow ${z}.`,J)})},Math.max(1,Math.floor(X/3)));A.unref?.();let F=G.status==="cancelling",U=new Z0({workflowId:z,owner:$,store:Y,steps:H.steps,cancelling:F,findBatch:(J)=>this.queue.driver.findBatch?.(J,{progress:!1})??Promise.resolve(null),buildBatch:(J,P,N)=>this.queue.buildBatch(J,P.map((D)=>JSON.stringify(D)),{name:N.name,allowFailures:N.allowFailures,finally:{name:I,args:[z]}}),scheduled:()=>this.queue.claimSoon(),cancelCheckMs:p0});try{let J;try{let P=new B,N=await(F?P.onCancel(U,...K):P.run(U,...K));J=U.suspension?{kind:"suspended"}:{kind:"completed",result:F?null:m(N,`The result of ${G.name}`)}}catch(P){if(J=U.suspension||P instanceof g?{kind:"suspended"}:{kind:"failed",error:a(P)},P instanceof R)U.lost=!0}if(await U.settled(),U.lost)return;if(J.kind==="completed"&&U.suspension)J={kind:"suspended"};await Y.update(z,{owner:$},({workflow:P,now:N})=>this.finish(P,J,U,F,N)),this.queue.claimSoon()}catch(J){if(J instanceof R)return;throw J}finally{clearInterval(A)}}finish(z,V,Y,Z,$){let X={result:void 0,unlock:!0};if(z.status==="cancelling"&&!Z)return{...X,tick:{delayMs:0}};if(V.kind==="completed")return{...X,workflow:Z?{status:"cancelled",currentStep:null,wakeAt:null}:{status:"completed",result:V.result,progress:1,currentStep:null,wakeAt:null,error:null}};if(V.kind==="failed")return{...X,workflow:{status:Z?"cancelled":"failed",error:V.error,wakeAt:null}};let H=Y.suspension??{status:"waiting",wakes:[]},G={...X,workflow:{status:Z?"cancelling":H.status,currentStep:Y.current??z.currentStep}};if(H.wakes.length>0){let Q=Math.min(...H.wakes);if(!(z.wakeAt!==null&&z.wakeAt>$&&z.wakeAt<=Q))G.tick={delayMs:Math.max(0,Q-$)},G.workflow.wakeAt=Q}return G}async unknown(z,V,Y){let Z=Date.now()-z.createdAt;if(this.queue.durable&&Z<this.queue.config.unknownJobGrace){if(!this.reportedNames.has(z.name))this.reportedNames.add(z.name),console.error(`Left workflow "${z.name}" for another replica: nothing is registered here under that name.`);await Y(),V.release(Math.round(this.queue.config.pollInterval*(1+Math.random())));return}console.error(`Failed workflow ${z.id}: nothing is registered under the name "${z.name}". If the class exists, it was not discovered: check that it is under the queue slice's workflowsDir (app/workflows by default), or list it in app/config/queue.ts.`),await Y({workflow:{status:"failed",error:`No workflow is registered under the name "${z.name}".`}})}tickDeadLettered(z,V){console.error(`[gemi] The tick of workflow ${z} was dead-lettered.`,V),this.store.update(z,{},({workflow:Y})=>r.includes(Y.status)?{result:void 0}:{result:void 0,workflow:{status:"failed",error:`Its tick job was dead-lettered: ${V.message}`},unlock:!0}).catch(()=>{})}}function w0(z){return class extends S{static name=I;maxAttempts=20;backoff=[1000,5000,15000,30000,60000];async run(Y){await z.tick(Y,this)}onDeadletter(Y,Z){z.tickDeadLettered(Z,Y)}}}function d0(z){try{return _(z)}catch{return z}}function i0(){let z=process.env.APP_DIR,V=process.env.ROOT_DIR,Y=Bun.env.NODE_ENV==="production"?`${V}/dist/server/bootstrap.mjs`:`${z}/bootstrap.ts`,Z=new File([`
|
|
395
|
+
)`]}function A0(z){let V=JSON.parse(z.options),Y=(Z)=>Z==null?null:Number(Z);return{id:String(z.id),name:z.name==null?null:String(z.name),total:Number(z.total),pending:Number(z.pending),succeeded:Number(z.succeeded),failed:Number(z.failed),cancelled:Number(z.cancelled),failedJobIds:JSON.parse(z.failed_job_ids),cancelledAt:Y(z.cancelled_at),finishedAt:Y(z.finished_at),createdAt:Number(z.created_at),allowFailures:V.allowFailures===!0,callbacks:V.callbacks??{}}}function m0(z){return JSON.stringify({allowFailures:z.allowFailures,callbacks:z.callbacks})}function _0(z){let V=String(z?.message??z);return/does not exist|doesn't exist|unknown column|no such (table|column)|has no column/i.test(V)}async function e(z,V){try{return await z}catch(Y){if(!_0(Y))throw Y;throw Error(`Job batches need the "${V}" table and the batch_id and progress columns of the jobs table, and the database says one is missing. Add the GemiJobBatch model and the two GemiJob fields from the docs (docs/jobs-and-queues.md#batches) and migrate, or call the driver's createTable().`,{cause:Y})}}function Nz(z){return z}function C0(){return{jobs:[],jobsDir:"app/jobs",workflows:[],workflowsDir:"app/workflows",concurrency:1,driver:"memory",visibilityTimeout:300000,pollInterval:1000,unknownJobGrace:3600000,locks:"auto"}}var b0=86400000;class V0{queue;workflows=new Map;steps=new Map;constructor(z){this.queue=z}async create(z){if(this.workflows.has(z.id))throw Error(`A workflow with the id ${z.id} already exists.`);this.prune(b0);let V=Date.now();this.workflows.set(z.id,{...z,status:"running",currentStep:null,progress:0,result:null,error:null,wakeAt:null,lockedBy:null,lockedUntil:null,retick:!1,createdAt:V,updatedAt:V}),this.steps.set(z.id,new Map),this.tick(z.id,0)}async find(z,V={}){let Y=this.workflows.get(z);if(!Y)return null;return{workflow:{...Y},steps:V.steps===!1?[]:this.stepsOf(z)}}async acquire(z,V,Y){let Z=this.workflows.get(z);if(!Z)return{kind:"missing"};let $=Date.now();if(Z.lockedBy!==null&&!w(Z.lockedBy,V)&&(Z.lockedUntil??0)>$)return Z.retick=!0,{kind:"busy"};return Z.lockedBy=V,Z.lockedUntil=$+Y,Z.retick=!1,{kind:"acquired",workflow:{...Z},steps:this.stepsOf(z)}}async renew(z,V,Y){let Z=this.workflows.get(z);if(!Z||Z.lockedBy!==V)return!1;return Z.lockedUntil=Date.now()+Y,!0}async update(z,V,Y){let Z=this.workflows.get(z);if(!Z)return;if(V.owner!==void 0&&Z.lockedBy!==V.owner)throw new R(z);let $=this.steps.get(z),X=V.key===void 0?void 0:$.get(V.key),H=Date.now(),G=Y({workflow:{...Z},step:X?{...X}:null,steps:V.allSteps?this.stepsOf(z):[],now:H});if(G.step){let Q=$.get(G.step.key);$.set(G.step.key,{...G.step,createdAt:Q?.createdAt??H,updatedAt:H})}if(G.batch)this.queue.enqueueBatch(G.batch);for(let Q of G.cancelBatches??[])this.queue.cancelBatch(Q);if(G.workflow)Object.assign(Z,G.workflow);if(Z.updatedAt=H,G.tick)this.tick(z,G.tick.delayMs);if(G.unlock){if(Z.lockedBy=null,Z.lockedUntil=null,Z.retick)Z.retick=!1,this.tick(z,0)}return G.result}async prune(z){let V=Date.now()-z,Y=0;for(let[Z,$]of this.workflows)if(["completed","failed","cancelled"].includes($.status)&&$.updatedAt<=V)this.workflows.delete(Z),this.steps.delete(Z),Y++;return Y}stepsOf(z){return[...this.steps.get(z)?.values()??[]].map((V)=>({...V}))}tick(z,V){this.queue.enqueue({name:I,args:JSON.stringify([z]),delayMs:Math.max(0,Math.round(V))})}}var u0=86400000;class i{entries=new Map;batches=new Map;workflows;listeners=new Set;timer;timerAt=1/0;seq=0;get waiting(){let z=0;for(let V of this.entries.values())if(!V.leased)z++;return z}get leased(){return this.entries.size-this.waiting}async enqueue(z){let V=this.add(z);return this.changed(),V}add({name:z,args:V,delayMs:Y=0,id:Z=crypto.randomUUID()},$){let X=Date.now();return this.entries.set(Z,{job:{id:Z,name:z,args:V,attempt:0,createdAt:X,...$===void 0?{}:{batchId:$}},until:X+Math.max(0,Y),leased:!1,seq:this.seq++,progress:0}),Z}async enqueueBatch(z){this.recordBatch(z)}recordBatch(z){let V=Date.now();this.forgetFinishedBatches(V);let Y=d({...z,total:z.args.length,now:V});for(let X of z.args)this.add({name:z.job,args:X},z.id);let{record:Z,calls:$}=x(Y,Y,V);this.batches.set(z.id,Z);for(let X of $)this.add(X);this.changed()}async findBatch(z,V={}){let Y=this.batches.get(z);if(!Y)return null;if(V.progress===!1||Y.pending===0)return W(Y);let Z=0;for(let $ of this.entries.values())if($.job.batchId===z)Z+=$.progress;return W(Y,Z)}async cancelBatch(z){return this.cancelBatchNow(z)}cancelBatchNow(z){let V=this.batches.get(z);if(!V||V.finishedAt!==null||V.cancelledAt!==null)return!1;let Y=Date.now(),Z=M(V,Y,this.cancelWaiting(z));return this.save(V,Z,Y),this.changed(),!0}workflowStore(){return this.workflows??=new V0({enqueue:(z)=>{this.add(z),this.changed()},enqueueBatch:(z)=>this.recordBatch(z),cancelBatch:(z)=>void this.cancelBatchNow(z)}),this.workflows}async reportProgress(z,V){let Y=this.current(z);if(Y)Y.progress=E(V)}async claim(z,V){let Y=Date.now(),Z=[...this.entries.values()].filter(($)=>$.until<=Y).sort(($,X)=>$.until-X.until||$.seq-X.seq).slice(0,Math.max(0,z));for(let $ of Z)$.job={...$.job,attempt:$.job.attempt+1},$.leased=!0,$.until=Y+V.visibilityTimeoutMs;if(Z.length>0)this.schedule();return Z.map(($)=>({...$.job}))}async complete(z){let V=this.current(z);if(!V)return;this.entries.delete(z.id),this.count(V,"succeeded"),this.schedule()}async fail(z,V){let Y=this.current(z);if(!Y)return;let Z=Y.job.batchId===void 0?void 0:this.batches.get(Y.job.batchId),$=V.cancelled===!0||V.retryInMs!==null&&Z?.cancelledAt!=null;if(V.retryInMs===null||$){this.entries.delete(z.id),this.count(Y,$?"cancelled":"failed"),this.schedule();return}Y.leased=!1,Y.until=Date.now()+Math.max(0,V.retryInMs),Y.seq=this.seq++,Y.progress=0,this.changed()}async release(z,V){let Y=this.current(z);if(!Y)return;Y.job={...Y.job,attempt:Y.job.attempt-1},Y.leased=!1,Y.until=Date.now()+Math.max(0,V.retryInMs),Y.seq=this.seq++,this.changed()}async heartbeat(z,V){let Y=Date.now()+V.visibilityTimeoutMs;for(let Z of z){let $=this.current(Z);if($)$.until=Y}this.schedule()}count(z,V){let Y=z.job.batchId;if(Y===void 0)return;let Z=this.batches.get(Y);if(!Z)return;let $=Date.now(),X=c(Z,V,z.job.id);if(l(Z,X))X=M(X,$,this.cancelWaiting(Y));this.save(Z,X,$),this.changed()}save(z,V,Y){let{record:Z,calls:$}=x(z,V,Y);this.batches.set(Z.id,Z);for(let X of $)this.add(X)}cancelWaiting(z){let V=0;for(let[Y,Z]of this.entries)if(Z.job.batchId===z&&!Z.leased)this.entries.delete(Y),V++;return V}forgetFinishedBatches(z){for(let[V,Y]of this.batches)if(Y.finishedAt!==null&&z-Y.finishedAt>u0)this.batches.delete(V)}subscribe(z){return this.listeners.add(z),()=>void this.listeners.delete(z)}current(z){let V=this.entries.get(z.id);if(!V||!V.leased||V.job.attempt!==z.attempt)return;return V}changed(){this.schedule();let z=Date.now();for(let V of this.entries.values())if(V.until<=z){this.wake();return}}wake(){for(let z of[...this.listeners])z()}schedule(){let z=Date.now(),V=1/0;for(let Y of this.entries.values())if(Y.until>z&&Y.until<V)V=Y.until;if(V===this.timerAt)return;if(clearTimeout(this.timer),this.timer=void 0,this.timerAt=V,V===1/0)return;this.timer=setTimeout(()=>{this.timer=void 0,this.timerAt=1/0,this.changed()},V-z),this.timer.unref?.()}}function s(z,V){let Y=Array.isArray(z)?z[Math.min(V,z.length)-1]:z;return Math.max(0,Y??0)}var k0={ms:1,s:1000,m:60000,h:3600000,d:86400000,w:604800000};function n(z){if(typeof z==="number"){if(!Number.isFinite(z)||z<0)throw TypeError(`A duration is 0 or more milliseconds; got ${z}.`);return Math.round(z)}let V=/^\s*(\d+(?:\.\d+)?)\s*(ms|s|m|h|d|w)\s*$/.exec(String(z));if(!V)throw TypeError(`"${String(z)}" is not a duration. Use milliseconds, or a number and one of ms, s, m, h, d, w ("30s", "7d").`);return Math.round(Number(V[1])*k0[V[2]])}class I0 extends Error{step;batch;constructor(z,V,Y){super(V);this.step=z;this.batch=Y;this.name="StepFailedError"}}class Y0 extends Error{step;constructor(z){super(`No signal "${z}" arrived before its timeout.`);this.step=z;this.name="WaitTimeoutError"}}class E0 extends Error{constructor(z,V){super(`Step "${z}" took longer than its timeout of ${V}ms.`);this.name="StepTimeoutError"}}class O0 extends Error{constructor(z){super(`Workflow ${z} was cancelled.`);this.name="WorkflowCancelledError"}}class g extends Error{constructor(){super("The workflow is suspended until a step can continue. Rethrow this error if you catch it.");this.name="WorkflowSuspended"}}var D0=Symbol("done");class Z0{tick;workflowId;steps;seen=new Set;pending=new Set;suspension;lost=!1;cancelled=!1;current=null;constructor(z){this.tick=z;this.workflowId=z.workflowId,this.steps=new Map(z.steps.map((V)=>[V.key,V]))}run(z,V,Y={}){return this.track(z,()=>this.runStep(z,V,Y))}sleep(z,V){let Y=n(V);return this.track(z,()=>this.sleepStep(z,Y))}waitFor(z,V={}){let Y=V.timeout===void 0?void 0:n(V.timeout);return this.track(z,()=>this.waitStep(z,Y))}batch(z,V,Y,Z={}){return this.track(z,()=>this.batchStep(z,V,Y,Z))}async progress(z){let V=E(z);this.assertRunning();let Y=this.write(void 0,()=>({result:void 0,workflow:{progress:V}}));this.remember(Y),await Y}async settled(){while(this.pending.size>0)await Promise.allSettled(this.pending)}track(z,V){if(typeof z!=="string"||z.length===0||z.length>191)throw TypeError(`A step key is a string of 1 to 191 characters; got ${JSON.stringify(z)}.`);if(this.seen.has(z))throw Error(`Two steps of workflow ${this.workflowId} use the key "${z}". Each step needs a key of its own, or the second would return the first one's result.`);this.seen.add(z),this.assertRunning();let Y=V();return this.remember(Y),Y}remember(z){this.pending.add(z);let V=()=>void this.pending.delete(z);z.then(V,V)}assertRunning(){if(this.lost)throw new R(this.workflowId);if(this.suspension)throw new g}suspend(z,V){if(!this.suspension)this.suspension={status:z,wakes:[]};if(V!=null)this.suspension.wakes.push(V);throw new g}async write(z,V){let Y;try{Y=await this.tick.store.update(this.tick.workflowId,{owner:this.tick.owner,...z===void 0?{}:{key:z}},(Z)=>{if(Z.workflow.status==="cancelling"&&!this.tick.cancelling)return{result:D0};let $=V(Z);return{...$,result:{value:$.result}}})}catch(Z){if(Z instanceof R)this.lost=!0;throw Z}if(Y===void 0)throw this.lost=!0,new R(this.tick.workflowId);if(Y===D0)this.cancelled=!0,this.suspend("waiting");return Y.value}record(z,V,Y){let Z={workflowId:this.tick.workflowId,key:z,status:"running",attempt:0,output:null,error:null,batchId:null,wakeAt:null,startedAt:null,finishedAt:null,createdAt:0,updatedAt:0,...V,...Y};return this.steps.set(z,Z),Z}mismatch(z,V,Y){throw Error(`Step "${z}" of workflow ${this.tick.workflowId} was recorded as a ${V} step, and is now used as ${Y}. A key belongs to one step; rename one of them.`)}async runStep(z,V,Y){let Z=Math.max(1,Math.floor(Y.attempts??3)),$=Y.timeout===void 0?void 0:n(Y.timeout),X=this.steps.get(z);if(X?.status==="completed")return _(X.output);if(X?.status==="failed")throw j(z,X);if(X?.status==="retrying"&&X.wakeAt!==null&&X.wakeAt>Date.now())this.current=z,this.suspend("sleeping",X.wakeAt);for(;;){let H=await this.write(z,({workflow:J,step:P,now:N})=>{if(P?.status==="completed")return{result:{kind:"done",output:P.output}};if(P?.status==="failed")return{result:{kind:"failed",step:P}};if(P&&P.status!=="running"&&P.status!=="retrying")this.mismatch(z,P.status,"step.run");if(P?.status==="retrying"&&P.wakeAt!==null&&P.wakeAt>N)return{result:{kind:"wait",wakeAt:P.wakeAt}};let D=(P?.attempt??0)+1;if(D>Z){let G0=this.record(z,P,{status:"failed",error:`Attempt ${D-1} of ${Z} never finished, most likely because the process running it exited.`+(P?.error?` The last error was: ${P.error}`:""),finishedAt:N,wakeAt:null});return{result:{kind:"failed",step:G0},step:G0}}let u=this.record(z,P,{status:"running",attempt:D,startedAt:N,finishedAt:null,wakeAt:null});return{result:{kind:"run",attempt:D},step:u,workflow:J.status==="cancelling"?{currentStep:z}:{currentStep:z,status:"running"}}});if(this.current=z,H.kind==="done")return _(H.output);if(H.kind==="failed")throw j(z,H.step);if(H.kind==="wait")this.suspend("sleeping",H.wakeAt);let G=H.attempt,Q,B,K=!0;try{Q=await this.execute(z,V,G,$)}catch(J){B=J}if(this.cancelled)throw new g;let A=null;if(B===void 0)try{A=m(Q,`The result of step "${z}"`)}catch(J){B=J,K=!1}if(B===void 0)return await this.write(z,({step:J,now:P})=>({result:void 0,step:this.record(z,J,{status:"completed",output:A,error:null,wakeAt:null,finishedAt:P})})),_(A);let F=a(B);if(K&&G<Z){let J=s(Y.backoff??0,G),P=await this.write(z,({step:N,now:D})=>{let u=J>0?D+J:null;return{result:u,step:this.record(z,N,{status:"retrying",error:F,wakeAt:u})}});if(P!==null)this.suspend("sleeping",P);continue}let U=await this.write(z,({step:J,now:P})=>{let N=this.record(z,J,{status:"failed",error:F,wakeAt:null,finishedAt:P});return{result:N,step:N}});throw j(z,U)}}async execute(z,V,Y,Z){let $=new AbortController,X={idempotencyKey:`${this.tick.workflowId}:${z}`,attempt:Y,signal:$.signal},H=Promise.resolve().then(()=>V(X)),G,Q,B=new Promise((K,A)=>{let F=(U)=>{$.abort(U),A(U)};if(Z!==void 0)G=setTimeout(()=>F(new E0(z,Z)),Z);if(!this.tick.cancelling)Q=setInterval(()=>{this.tick.store.find(this.tick.workflowId,{steps:!1}).then((U)=>{if(U?.workflow.status!=="cancelling"||$.signal.aborted)return;if(this.cancelled=!0,!this.suspension)this.suspension={status:"waiting",wakes:[]};F(new O0(this.tick.workflowId))}).catch(()=>{})},this.tick.cancelCheckMs),Q.unref?.()});try{return await Promise.race([H,B])}finally{clearTimeout(G),clearInterval(Q),H.catch(()=>{}),B.catch(()=>{})}}async sleepStep(z,V){let Y=this.steps.get(z);if(Y?.status==="completed")return;if(this.current=z,Y?.status==="sleeping"&&Y.wakeAt!==null&&Y.wakeAt>Date.now())this.suspend("sleeping",Y.wakeAt);let Z=await this.write(z,({step:$,now:X})=>{if($?.status==="completed")return{result:null};if($&&$.status!=="sleeping")this.mismatch(z,$.status,"step.sleep");let H=$?.wakeAt??X+V;if(H<=X)return{result:null,step:this.record(z,$,{status:"completed",wakeAt:H,startedAt:$?.startedAt??X,finishedAt:X})};if($)return{result:H};return{result:H,step:this.record(z,null,{status:"sleeping",wakeAt:H,startedAt:X}),workflow:{currentStep:z}}});if(Z!==null)this.suspend("sleeping",Z)}async waitStep(z,V){let Y=this.steps.get(z);if(Y?.status==="completed")return _(Y.output);if(Y?.status==="timed_out")throw new Y0(z);if(this.current=z,Y?.status==="waiting"&&(Y.wakeAt===null||Y.wakeAt>Date.now()))this.suspend("waiting",Y.wakeAt);let Z=await this.write(z,({step:$,now:X})=>{if($?.status==="completed")return{result:{kind:"value",output:$.output}};if($?.status==="timed_out")return{result:{kind:"timeout"}};if($?.status==="signalled")return{result:{kind:"value",output:$.output},step:this.record(z,$,{status:"completed",wakeAt:null,startedAt:$.startedAt??X,finishedAt:X})};if($&&$.status!=="waiting")this.mismatch(z,$.status,"step.waitFor");if($){if($.wakeAt!==null&&$.wakeAt<=X)return{result:{kind:"timeout"},step:this.record(z,$,{status:"timed_out",finishedAt:X})};return{result:{kind:"wait",wakeAt:$.wakeAt}}}let H=V===void 0?null:X+V;return{result:{kind:"wait",wakeAt:H},step:this.record(z,null,{status:"waiting",wakeAt:H,startedAt:X}),workflow:{currentStep:z}}});if(Z.kind==="value")return _(Z.output);if(Z.kind==="timeout")throw new Y0(z);this.suspend("waiting",Z.wakeAt)}async batchStep(z,V,Y,Z){let $=Z.allowFailures===!0,X=this.steps.get(z);if(X?.status==="completed")return _(X.output);if(X?.status==="failed")throw j(z,X);if(X&&X.status!=="batching")this.mismatch(z,X.status,"step.batch");if(this.current=z,!X){let A=this.tick.buildBatch(V,Y,{name:Z.name??`workflow:${this.tick.workflowId}:${z}`,allowFailures:$});if(X=await this.write(z,({step:F,now:U})=>{if(F)return{result:F};let J=this.record(z,null,{status:"batching",batchId:A.id,startedAt:U});return{result:J,step:J,batch:A,workflow:{currentStep:z}}}),this.tick.scheduled(),X.status==="completed")return _(X.output);if(X.status==="failed")throw j(z,X)}let H=X.batchId===null?null:await this.tick.findBatch(X.batchId);if(H&&H.finishedAt===null)this.suspend("waiting");let G=H!==null&&H.cancelledAt===null&&(H.failed===0||$),Q=H===null?null:JSON.stringify(H),B=G?null:H===null?`The batch of step "${z}" (${X.batchId}) no longer exists.`:`The batch of step "${z}" failed: ${H.failed} failed and ${H.cancelled} cancelled of ${H.total}.`,K=await this.write(z,({step:A,now:F})=>{let U=this.record(z,A,{status:G?"completed":"failed",output:Q,error:B,finishedAt:F});return{result:U,step:U}});if(!G)throw j(z,K);return H}}function j(z,V){let Y=V.batchId!==null&&V.output!==null?JSON.parse(V.output):void 0;return new I0(z,Y?V.error??`Step "${z}" failed.`:`Step "${z}" failed: ${V.error??"unknown error"}`,Y)}function m(z,V){if(z===void 0)return null;let Y=JSON.stringify(z);if(Y===void 0)throw TypeError(`${V} cannot be stored: JSON has no form for it.`);let Z=Buffer.byteLength(Y,"utf8");if(Z>t)throw RangeError(`${V} is ${Z} bytes as JSON, over the ${t}-byte limit. Store it elsewhere and return its id.`);return Y}function _(z){return z===null?void 0:JSON.parse(z)}function a(z){return z instanceof Error?z.message:String(z)}import{AsyncResource as p0}from"async_hooks";import{isMainThread as w0}from"worker_threads";function d0(){let z=process.env.APP_DIR,V=process.env.ROOT_DIR,Y=Bun.env.NODE_ENV==="production"?`${V}/dist/server/bootstrap.mjs`:`${z}/bootstrap.ts`,Z=new File([`
|
|
396
396
|
import { app } from "${Y}"
|
|
397
397
|
self.onmessage = async (event) => {
|
|
398
398
|
const clone = app.clone()
|
|
@@ -410,7 +410,7 @@ ADD COLUMN IF NOT EXISTS "progress" ${Y}`,`CREATE INDEX IF NOT EXISTS "${V}_batc
|
|
|
410
410
|
self.postMessage({result});
|
|
411
411
|
}
|
|
412
412
|
};
|
|
413
|
-
`],"worker.ts"),$=URL.createObjectURL(Z);return new Worker($)}async function s0(z,V){let Y=i0();return Y.postMessage({jobName:z,args:V}),await new Promise((Z,$)=>{Y.onmessage=(X)=>{let H=X.data;if("error"in H)$(H.error);else Z(H.result)}})}var n0=new c0("gemi.queue"),a0=60000;class h{static token="queue";jobs={};config;driver;application;inFlight=new Map;state="idle";looping=!1;claiming;woken=!1;claimFailures=0;resume;unsubscribe;heartbeatTimer;releasedNames=new Set;lockManager;workflowRuntime;constructor(z={},V={}){if(this.config=S0(C0(),z),this.application=V.application,this.driver=zz(this.config.driver,this.application),this.useJobs(this.config.jobs),this.config.workflows.length>0)this.useWorkflows(this.config.workflows)}useJobs(z){this.config.jobs=z,this.jobs={};for(let V of z)this.claim(V);this.registerTickJob()}useWorkflows(z){this.config.workflows=z,this.workflows.use(z),this.registerTickJob()}get registeredWorkflows(){return[...this.config.workflows]}get workflows(){return this.workflowRuntime??=new $0(this),this.workflowRuntime}registerTickJob(){if(!this.workflowRuntime||Object.keys(this.workflowRuntime.workflows).length===0)return;let z=this.workflowRuntime.tickJob;if(this.jobs[z.name]&&this.jobs[z.name]!==z){console.error(`A queued job is named "${z.name}", which the workflow runtime uses. Workflows will not run until it is renamed.`);return}this.jobs[z.name]=z}registerJob(z){this.config.jobs=[...this.config.jobs,z],this.claim(z)}claim(z){if(this.jobs[z.name]){console.error(`Two queued jobs are named "${z.name}" \u2014 the first is registered `+"and this one is not, so dispatching either would have run one of them. A class name is the queue's key, so only one job can hold it. Rename one.");return}this.jobs[z.name]=z}get registeredJobs(){return[...this.config.jobs]}dispatchJob(z,V){if(this.jobs[z])return new this.jobs[z]().run(JSON.parse(V))}push(z,V,Y={}){let Z=this.uniqueKey(z,V);if(Z)return this.pushUnique(z,V,Z,Y);let $=this.driver.joinsTransaction?.()===!0;if(!$){let X=Bun.randomUUIDv7();if(C(()=>this.record(z,V,{id:X,reportFailure:!0,committed:!0}).then(()=>{},()=>{})))return Promise.resolve(X)}return this.record(z,V,{reportFailure:Y.reportFailure,joins:$})}pushBatch(z,V,Y={}){let Z=this.buildBatch(z,V,Y),$={id:Z.id,total:V.length},X=this.driver.joinsTransaction?.()===!0;if(!X){if(C(()=>this.recordBatch(Z,{committed:!0}).then(()=>{},()=>{})))return Promise.resolve($)}return this.recordBatch(Z,{joins:X}).then(()=>$)}buildBatch(z,V,Y={}){if(!this.driver.enqueueBatch)throw Error("This queue's driver does not support batches. The memory and database drivers do.");if(new z().worker)throw Error(`${z.name} is a worker job, and a worker job cannot be dispatched in a batch: its thread has no way to report progress or reach the batch.`);if(z.prototype.uniqueId!==S.prototype.uniqueId)throw Error(`${z.name} is unique (it defines uniqueId), and a unique job cannot be dispatched in a batch: a duplicate would resolve to a job outside the batch, and the batch would wait for it forever.`);let $={};for(let X of["then","catch","finally"]){let H=Y[X];if(H===void 0)continue;if(typeof H?.name!=="string"||!Array.isArray(H.args))throw Error(`The batch's ${X} callback is not a job call. Build it with SomeJob.with(...args).`);$[X]={name:H.name,args:H.args}}return{id:Bun.randomUUIDv7(),name:Y.name??null,job:z.name,args:V,allowFailures:Y.allowFailures===!0,callbacks:$}}recordBatch(z,V){let Y=this.driver.enqueueBatch(z);this.startIfIdle();let Z=()=>!this.driver.subscribe&&this.state==="running"&&this.wake(),$=V.joins===!0&&C(Z);return Y.then(()=>$||Z(),(X)=>{if(!V.committed)return;console.error(`[gemi] The queue driver could not record a batch of ${z.job}, which was held until its transaction committed. The transaction stays committed; the batch's jobs did not run and will not be retried.`,X)}),Y}async findBatch(z){if(!this.driver.findBatch)throw Error("This queue's driver does not support batches.");return this.driver.findBatch(z)}async cancelBatch(z){if(!this.driver.cancelBatch)throw Error("This queue's driver does not support batches.");let V=await this.driver.cancelBatch(z);if(V)this.claimSoon();return V}get locks(){return this.lockManager??=new T0(this.resolveLockStore()),this.lockManager}resolveLockStore(){let z=this.config.locks;if(z==="auto"){let V=this.driver.lockStore?.();if(V)return V;if(this.durable)console.warn('[gemi] The queue driver keeps no locks, so unique jobs, withoutOverlapping and onOneServer only hold within this process. Set the queue slice\'s `locks` to "database" or a LockStore.');return new p}if(z==="memory")return new p;if(z==="database"||typeof z==="function"){if(!this.application&&(z==="database"||z.length>0))throw Error("The queue's locks need the application they belong to, and this QueueManager was built without one. Pass { application }.");if(z==="database")return new y(this.application.make(H0));return z(this.application)}if(typeof z==="string")throw Error(`Unknown queue locks "${z}". The queue slice's locks is "auto", "memory", "database", a LockStore, or a function returning one.`);return z}uniqueKey(z,V){if(z.prototype.uniqueId===S.prototype.uniqueId)return;let Y=new z,Z=Y.uniqueId(...JSON.parse(V));if(Z===void 0||Z===null||Z==="")return;return{key:L0(z.name,Z),ttl:Math.max(1,Y.uniqueFor)}}pushUnique(z,V,Y,Z){let $=Bun.randomUUIDv7();if(C(()=>this.recordUnique(z,V,Y,$,{report:!0,committed:!0}).then(()=>{},()=>{})))return Promise.resolve($);return this.recordUnique(z,V,Y,$,{report:Z.reportFailure!==!1,committed:!1})}recordUnique(z,V,Y,Z,$){let X=this.locks.store,H=(async()=>{for(let G=0;G<5;G++){if(await X.acquire(Y.key,Z,Y.ttl)!==null)try{return await this.record(z,V,{id:Z,reportFailure:!1})}catch(B){throw await X.release(Y.key,Z).catch(()=>{}),B}let Q=await X.holder(Y.key);if(Q)return Q.owner}throw Error(`The unique key "${Y.key}" kept changing hands, so ${z.name} was not queued.`)})();return H.catch((G)=>{if(!$.report)return;console.error(`[gemi] The queue could not record the unique job ${z.name}`+($.committed?", which was held until its transaction committed. The transaction stays committed; the job did not run and will not be retried.":", so it did not run and will not be retried."),G)}),H}async releaseUnique(z,V,Y){if(z.uniqueId===S.prototype.uniqueId)return;try{let Z=z.uniqueId(...V);if(Z===void 0||Z===null||Z==="")return;await this.locks.store.release(L0(Y.name,Z),Y.id)}catch(Z){console.error(`[gemi] Could not free the unique key of ${Y.name} (${Y.id}); it frees itself after uniqueFor.`,Z)}}record(z,V,Y){let Z=this.driver.enqueue({name:z.name,args:V,...Y.id===void 0?{}:{id:Y.id}});this.startIfIdle();let $=()=>!this.driver.subscribe&&this.state==="running"&&this.wake(),X=Y.joins===!0&&C($);return Z.then(()=>X||$(),(H)=>{if(Y.reportFailure===!1)return;console.error(`[gemi] The queue driver could not record ${z.name}`+(Y.committed?", which was held until its transaction committed. The transaction stays committed; the job did not run and will not be retried.":", so it did not run and will not be retried."),H)}),Z}async retryDead(z){if(!this.driver.retryDead)throw Error("This queue's driver keeps nothing of a dead-lettered job, so there is nothing to retry. The database driver keeps them.");let V=await this.driver.retryDead(z);if(V)this.claimSoon();return V}startIfIdle(){if(this.state==="idle"&&(!this.durable||this.mayClaimHere()))this.start()}claimSoon(){if(this.startIfIdle(),!this.driver.subscribe&&this.state==="running")this.wake()}start(){if(this.state==="running")return;if(this.state="running",this.durable&&this.application&&this.mayClaimHere()&&!r0())globalThis.__gemiDevQueue=this;if(this.unsubscribe=this.driver.subscribe?.(()=>this.wake()),this.looping)return this.wake();n0.runInAsyncScope(()=>void this.loop())}async drain(z=1/0){if(this.state="stopped",globalThis.__gemiDevQueue===this)globalThis.__gemiDevQueue=void 0;this.unsubscribe?.(),this.unsubscribe=void 0,this.wake();let V,Y=new Promise(($)=>{if(z!==1/0)V=setTimeout($,z)}),Z=(async()=>{await this.claiming?.catch(()=>{}),await Promise.allSettled([...this.inFlight.values()].map(($)=>$.done))})();return await Promise.race([Z,Y]),clearTimeout(V),{unfinished:[...this.inFlight.values()].map(($)=>({...$.job}))}}stop(){return this.drain(0)}get running(){return this.inFlight.size}async loop(){this.looping=!0;try{await this.claimWhileRunning()}finally{this.looping=!1}}async claimWhileRunning(){while(this.state==="running"){let z=this.durable&&M0()?0:this.config.concurrency-this.inFlight.size;if(z>0){this.woken=!1;let V=this.driver.claim(z,{...this.lease(),registered:{names:Object.keys(this.jobs),graceMs:this.config.unknownJobGrace}});this.claiming=V;let Y=[];try{Y=await V,this.claimFailures=0}catch(Z){this.claimFailures++,console.error(`The queue could not claim jobs from its driver; it will try again in ${this.retryDelay()}ms.`,Z)}finally{this.claiming=void 0}for(let Z of Y)this.execute(Z);if(Y.length===z)continue;if(this.woken&&this.inFlight.size<this.config.concurrency)continue}await this.sleep()}}sleep(){return new Promise((z)=>{let V,Y=this.claimFailures>0?this.retryDelay():this.driver.subscribe?void 0:this.config.pollInterval;if(Y!==void 0)V=setTimeout(()=>this.wake(),Y),V.unref?.();this.resume=()=>{clearTimeout(V),z()}})}retryDelay(){let z=Math.min(Math.max(0,this.claimFailures-1),30);return Math.min(this.config.pollInterval*2**z,a0)}wake(){this.woken=!0;let z=this.resume;this.resume=void 0,z?.()}get durable(){return!(this.driver instanceof i)}mayClaimHere(){return!this.application||t0()}lease(){return{visibilityTimeoutMs:this.config.visibilityTimeout}}execute(z){let V=`${z.id}:${z.attempt}`,Y=()=>this.run(z),Z=(this.application?W0.run(this.application,Y):Y()).catch(($)=>{console.error(`The queue could not record the outcome of ${z.name}.`,$)}).finally(()=>{this.inFlight.delete(V),this.wake()});this.inFlight.set(V,{job:z,done:Z}),this.heartbeat()}heartbeat(){let z=this.driver;if(!z.heartbeat||this.heartbeatTimer)return;this.heartbeatTimer=setInterval(()=>{if(this.inFlight.size===0){clearInterval(this.heartbeatTimer),this.heartbeatTimer=void 0;return}let V=[...this.inFlight.values()].map((Y)=>Y.job);z.heartbeat(V,this.lease()).catch((Y)=>{console.error("The queue could not extend its job leases.",Y)})},Math.max(1,Math.floor(this.config.visibilityTimeout/3))),this.heartbeatTimer.unref?.()}async run(z){let V=this.jobs[z.name];if(!V){let B=Date.now()-z.createdAt;if(this.durable&&B<this.config.unknownJobGrace){if(!this.releasedNames.has(z.name))this.releasedNames.add(z.name),console.error(`Left a queued "${z.name}" for another replica: nothing is registered here under that name. It is dead-lettered if no replica has run it within unknownJobGrace (${this.config.unknownJobGrace}ms) of its dispatch.`);await this.driver.release(z,{retryInMs:Math.round(this.config.pollInterval*(1+Math.random()))});return}console.error(`Dropped a queued job: nothing is registered under the name "${z.name}". If the class exists, it was not `+"discovered \u2014 check that it is under the queue slice's jobsDir "+"(app/jobs by default), or list it in app/config/queue.ts."),await this.driver.fail(z,{error:`No job is registered under the name "${z.name}".`,retryInMs:null});return}let Y;try{Y=new V}catch(B){console.error(`Dropped a queued ${z.name}: it could not be constructed.`,B),await this.driver.fail(z,{error:`The job could not be constructed: ${String(B)}`,retryInMs:null});return}let Z;try{Z=JSON.parse(z.args)}catch(B){console.error(`Dropped a queued ${z.name}: its arguments are not JSON.`,B),await this.driver.fail(z,{error:`The arguments are not JSON: ${String(B)}`,retryInMs:null});return}if(z.attempt>Math.max(1,Y.maxAttempts)){let B=Error(`${z.name} was claimed for attempt ${z.attempt} of ${Y.maxAttempts}: an earlier attempt never finished, most likely because the process running it exited. Dead-lettered without running it again.`);X0(`${z.name}.onDeadletter`,()=>Y.onDeadletter(B,...Z)),await this.driver.fail(z,{error:B.message,retryInMs:null}),await this.releaseUnique(Y,Z,z);return}if(Y.$claimed={...z},z.batchId!==void 0){if((await this.driver.findBatch?.(z.batchId,{progress:!1}))?.cancelledAt!=null){await this.driver.fail(z,{error:"Its batch was cancelled before it ran.",retryInMs:null,cancelled:!0});return}let K=this.batchHandle(z);Y.batch=K.batch,Y.$progress=K.progress}let $=await this.admit(Y,Z,z);if(!$)return;let X,H;try{H=await(Y.worker?s0(z.name,z.args):Y.run(...Z))}catch(B){X=B}finally{await $.done()}let G=Y.$outcome;if(X===void 0&&G?.kind==="release"){await this.driver.release(z,{retryInMs:Math.max(0,G.delayMs)});return}if(X===void 0&&G?.kind==="fail")X=G.error;let Q=G?.kind==="fail"?G.retry:!0;if(X===void 0)try{Y.onSuccess(H,...Z)}catch(B){X=B}if(X!==void 0){let B=String(X?.stack??X);if(X0(`${z.name}.onFail`,()=>Y.onFail(X,...Z)),!Q||z.attempt>=Y.maxAttempts)X0(`${z.name}.onDeadletter`,()=>Y.onDeadletter(X,...Z)),await this.driver.fail(z,{error:B,retryInMs:null}),await this.releaseUnique(Y,Z,z);else await this.driver.fail(z,{error:B,retryInMs:s(Y.backoff,z.attempt)});return}await this.driver.complete(z),await this.releaseUnique(Y,Z,z)}batchHandle(z){let V=z.batchId,Y=this.driver;return{batch:{id:V,cancelled:async()=>(await Y.findBatch?.(V,{progress:!1}))?.cancelledAt!=null},progress:(Z)=>Y.reportProgress?.(z,Z)??Promise.resolve()}}async admit(z,V,Y){let Z=z.concurrency(...V),$=[z.throttle(...V)??[]].flat();if(!Z&&$.length===0)return{done:async()=>{}};let X=this.locks,H;if(Z&&Z.limit>0){let Q=this.config.visibilityTimeout;for(let B=0;B<Z.limit&&!H;B++)H=await X.acquire(`gemi:concurrency:${Z.key}:${B}`,{ttl:Q,renew:!0})??void 0;if(!H){await this.driver.release(Y,{retryInMs:Math.round(this.config.pollInterval*(1+Math.random()))});return}}let G=[];for(let Q of $){let B=`gemi:throttle:${Q.key}`,K=await X.store.hit(B,Q.limit,Q.window);if(!K.allowed){await Promise.all(G.map((A)=>X.store.refund(A))),await H?.release(),await this.driver.release(Y,{retryInMs:Math.max(1,K.resetInMs)});return}G.push(B)}return{done:async()=>{await H?.release().catch((Q)=>{console.error(`[gemi] Could not free a concurrency slot of ${Y.name}.`,Q)})}}}}function L0(z,V){return`gemi:job:${z}:${String(V)}`}function X0(z,V){try{V()}catch(Y){console.error(`${z} threw; the job's claim was ended anyway.`,Y)}}function r0(){return Bun.env.NODE_ENV==="production"}function t0(){if(!l0)return!1;if(e0())return!0;return process.env.ROOT_DIR!==void 0&&!o0()}function o0(z=process.env){return(z.GEMI_QUEUE_CLAIM??"").trim().toLowerCase()==="off"}var x0=Symbol.for("gemi.queue.worker");function tz(z=!0){globalThis[x0]=z}function e0(){return globalThis[x0]===!0}function zz(z,V){if(z==="memory")return new i;if(z==="database"||typeof z==="function"){if(!V&&(z==="database"||z.length>0))throw Error("The queue driver needs the application it belongs to, and this QueueManager was built without one. Pass { application }.");if(z==="database")return new z0(V.make(H0));return z(V)}if(typeof z==="string")throw Error(`Unknown queue driver "${z}". The queue slice's driver is "memory", "database", a QueueDriver, or a function returning one.`);return z}class S{static name="unset";worker=!1;maxAttempts=3;backoff=0;uniqueId(...z){return}uniqueFor=3600000;throttle(...z){return}concurrency(...z){return}release(z=0){this.$outcome={kind:"release",delayMs:z}}fail(z,V={}){this.$outcome={kind:"fail",error:z instanceof Error?z:Error(String(z)),retry:V.retry??!0}}batch=void 0;async progress(z){let V=E(z);await this.$progress?.(V)}$progress;$claimed;$outcome;run(...z){}onFail(z,...V){}onSuccess(z,...V){}onDeadletter(z,...V){}static dispatch(...z){if(this.name==="unset")throw Error("Cannot dispatch a job with no name");return b(h).push(this,JSON.stringify(z))}static dispatchBatch(z,V={}){if(this.name==="unset")throw Error("Cannot dispatch a job with no name");return b(h).pushBatch(this,z.map((Y)=>JSON.stringify(Y)),V)}static with(...z){if(this.name==="unset")throw Error("Cannot use a job with no name as a callback");return JSON.stringify(z),{name:this.name,args:z}}static findBatch(z){return b(h).findBatch(z)}static cancelBatch(z){return b(h).cancelBatch(z)}}
|
|
414
|
-
export{
|
|
413
|
+
`],"worker.ts"),$=URL.createObjectURL(Z);return new Worker($)}async function c0(z,V){let Y=d0();return Y.postMessage({jobName:z,args:V}),await new Promise((Z,$)=>{Y.onmessage=(X)=>{let H=X.data;if("error"in H)$(H.error);else Z(H.result)}})}var l0=new p0("gemi.queue"),i0=60000;class h{static token="queue";jobs={};config;driver;application;inFlight=new Map;state="idle";looping=!1;claiming;woken=!1;claimFailures=0;resume;unsubscribe;heartbeatTimer;releasedNames=new Set;lockManager;workflowRuntime;constructor(z={},V={}){if(this.config=S0(C0(),z),this.application=V.application,this.driver=t0(this.config.driver,this.application),this.useJobs(this.config.jobs),this.config.workflows.length>0)this.useWorkflows(this.config.workflows)}useJobs(z){this.config.jobs=z,this.jobs={};for(let V of z)this.claim(V);this.registerTickJob()}useWorkflows(z){this.config.workflows=z,this.workflows.use(z),this.registerTickJob()}get registeredWorkflows(){return[...this.config.workflows]}get workflows(){return this.workflowRuntime??=new H0(this),this.workflowRuntime}registerTickJob(){if(!this.workflowRuntime||Object.keys(this.workflowRuntime.workflows).length===0)return;let z=this.workflowRuntime.tickJob;if(this.jobs[z.name]&&this.jobs[z.name]!==z){console.error(`A queued job is named "${z.name}", which the workflow runtime uses. Workflows will not run until it is renamed.`);return}this.jobs[z.name]=z}registerJob(z){this.config.jobs=[...this.config.jobs,z],this.claim(z)}claim(z){if(this.jobs[z.name]){console.error(`Two queued jobs are named "${z.name}" \u2014 the first is registered `+"and this one is not, so dispatching either would have run one of them. A class name is the queue's key, so only one job can hold it. Rename one.");return}this.jobs[z.name]=z}get registeredJobs(){return[...this.config.jobs]}dispatchJob(z,V){if(this.jobs[z])return new this.jobs[z]().run(JSON.parse(V))}push(z,V,Y={}){let Z=this.uniqueKey(z,V);if(Z)return this.pushUnique(z,V,Z,Y);let $=this.driver.joinsTransaction?.()===!0;if(!$){let X=Bun.randomUUIDv7();if(C(()=>this.record(z,V,{id:X,reportFailure:!0,committed:!0}).then(()=>{},()=>{})))return Promise.resolve(X)}return this.record(z,V,{reportFailure:Y.reportFailure,joins:$})}pushBatch(z,V,Y={}){let Z=this.buildBatch(z,V,Y),$={id:Z.id,total:V.length},X=this.driver.joinsTransaction?.()===!0;if(!X){if(C(()=>this.recordBatch(Z,{committed:!0}).then(()=>{},()=>{})))return Promise.resolve($)}return this.recordBatch(Z,{joins:X}).then(()=>$)}buildBatch(z,V,Y={}){if(!this.driver.enqueueBatch)throw Error("This queue's driver does not support batches. The memory and database drivers do.");if(new z().worker)throw Error(`${z.name} is a worker job, and a worker job cannot be dispatched in a batch: its thread has no way to report progress or reach the batch.`);if(z.prototype.uniqueId!==S.prototype.uniqueId)throw Error(`${z.name} is unique (it defines uniqueId), and a unique job cannot be dispatched in a batch: a duplicate would resolve to a job outside the batch, and the batch would wait for it forever.`);let $={};for(let X of["then","catch","finally"]){let H=Y[X];if(H===void 0)continue;if(typeof H?.name!=="string"||!Array.isArray(H.args))throw Error(`The batch's ${X} callback is not a job call. Build it with SomeJob.with(...args).`);$[X]={name:H.name,args:H.args}}return{id:Bun.randomUUIDv7(),name:Y.name??null,job:z.name,args:V,allowFailures:Y.allowFailures===!0,callbacks:$}}recordBatch(z,V){let Y=this.driver.enqueueBatch(z);this.startIfIdle();let Z=()=>!this.driver.subscribe&&this.state==="running"&&this.wake(),$=V.joins===!0&&C(Z);return Y.then(()=>$||Z(),(X)=>{if(!V.committed)return;console.error(`[gemi] The queue driver could not record a batch of ${z.job}, which was held until its transaction committed. The transaction stays committed; the batch's jobs did not run and will not be retried.`,X)}),Y}async findBatch(z){if(!this.driver.findBatch)throw Error("This queue's driver does not support batches.");return this.driver.findBatch(z)}async cancelBatch(z){if(!this.driver.cancelBatch)throw Error("This queue's driver does not support batches.");let V=await this.driver.cancelBatch(z);if(V)this.claimSoon();return V}get locks(){return this.lockManager??=new T0(this.resolveLockStore()),this.lockManager}resolveLockStore(){let z=this.config.locks;if(z==="auto"){let V=this.driver.lockStore?.();if(V)return V;if(this.durable)console.warn('[gemi] The queue driver keeps no locks, so unique jobs, withoutOverlapping and onOneServer only hold within this process. Set the queue slice\'s `locks` to "database" or a LockStore.');return new p}if(z==="memory")return new p;if(z==="database"||typeof z==="function"){if(!this.application&&(z==="database"||z.length>0))throw Error("The queue's locks need the application they belong to, and this QueueManager was built without one. Pass { application }.");if(z==="database")return new y(this.application.make(X0));return z(this.application)}if(typeof z==="string")throw Error(`Unknown queue locks "${z}". The queue slice's locks is "auto", "memory", "database", a LockStore, or a function returning one.`);return z}uniqueKey(z,V){if(z.prototype.uniqueId===S.prototype.uniqueId)return;let Y=new z,Z=Y.uniqueId(...JSON.parse(V));if(Z===void 0||Z===null||Z==="")return;return{key:L0(z.name,Z),ttl:Math.max(1,Y.uniqueFor)}}pushUnique(z,V,Y,Z){let $=Bun.randomUUIDv7();if(C(()=>this.recordUnique(z,V,Y,$,{report:!0,committed:!0}).then(()=>{},()=>{})))return Promise.resolve($);return this.recordUnique(z,V,Y,$,{report:Z.reportFailure!==!1,committed:!1})}recordUnique(z,V,Y,Z,$){let X=this.locks.store,H=(async()=>{for(let G=0;G<5;G++){if(await X.acquire(Y.key,Z,Y.ttl)!==null)try{return await this.record(z,V,{id:Z,reportFailure:!1})}catch(B){throw await X.release(Y.key,Z).catch(()=>{}),B}let Q=await X.holder(Y.key);if(Q)return Q.owner}throw Error(`The unique key "${Y.key}" kept changing hands, so ${z.name} was not queued.`)})();return H.catch((G)=>{if(!$.report)return;console.error(`[gemi] The queue could not record the unique job ${z.name}`+($.committed?", which was held until its transaction committed. The transaction stays committed; the job did not run and will not be retried.":", so it did not run and will not be retried."),G)}),H}async releaseUnique(z,V,Y){if(z.uniqueId===S.prototype.uniqueId)return;try{let Z=z.uniqueId(...V);if(Z===void 0||Z===null||Z==="")return;await this.locks.store.release(L0(Y.name,Z),Y.id)}catch(Z){console.error(`[gemi] Could not free the unique key of ${Y.name} (${Y.id}); it frees itself after uniqueFor.`,Z)}}record(z,V,Y){let Z=this.driver.enqueue({name:z.name,args:V,...Y.id===void 0?{}:{id:Y.id}});this.startIfIdle();let $=()=>!this.driver.subscribe&&this.state==="running"&&this.wake(),X=Y.joins===!0&&C($);return Z.then(()=>X||$(),(H)=>{if(Y.reportFailure===!1)return;console.error(`[gemi] The queue driver could not record ${z.name}`+(Y.committed?", which was held until its transaction committed. The transaction stays committed; the job did not run and will not be retried.":", so it did not run and will not be retried."),H)}),Z}async retryDead(z){if(!this.driver.retryDead)throw Error("This queue's driver keeps nothing of a dead-lettered job, so there is nothing to retry. The database driver keeps them.");let V=await this.driver.retryDead(z);if(V)this.claimSoon();return V}startIfIdle(){if(this.state==="idle"&&(!this.durable||this.mayClaimHere()))this.start()}claimSoon(){if(this.startIfIdle(),!this.driver.subscribe&&this.state==="running")this.wake()}start(){if(this.state==="running")return;if(this.state="running",this.durable&&this.application&&this.mayClaimHere()&&!s0())globalThis.__gemiDevQueue=this;if(this.unsubscribe=this.driver.subscribe?.(()=>this.wake()),this.looping)return this.wake();l0.runInAsyncScope(()=>void this.loop())}async drain(z=1/0){if(this.state="stopped",globalThis.__gemiDevQueue===this)globalThis.__gemiDevQueue=void 0;this.unsubscribe?.(),this.unsubscribe=void 0,this.wake();let V,Y=new Promise(($)=>{if(z!==1/0)V=setTimeout($,z)}),Z=(async()=>{await this.claiming?.catch(()=>{}),await Promise.allSettled([...this.inFlight.values()].map(($)=>$.done))})();return await Promise.race([Z,Y]),clearTimeout(V),{unfinished:[...this.inFlight.values()].map(($)=>({...$.job}))}}stop(){return this.drain(0)}get running(){return this.inFlight.size}async loop(){this.looping=!0;try{await this.claimWhileRunning()}finally{this.looping=!1}}async claimWhileRunning(){while(this.state==="running"){let z=this.durable&&M0()?0:this.config.concurrency-this.inFlight.size;if(z>0){this.woken=!1;let V=this.driver.claim(z,{...this.lease(),registered:{names:Object.keys(this.jobs),graceMs:this.config.unknownJobGrace}});this.claiming=V;let Y=[];try{Y=await V,this.claimFailures=0}catch(Z){this.claimFailures++,console.error(`The queue could not claim jobs from its driver; it will try again in ${this.retryDelay()}ms.`,Z)}finally{this.claiming=void 0}for(let Z of Y)this.execute(Z);if(Y.length===z)continue;if(this.woken&&this.inFlight.size<this.config.concurrency)continue}await this.sleep()}}sleep(){return new Promise((z)=>{let V,Y=this.claimFailures>0?this.retryDelay():this.driver.subscribe?void 0:this.config.pollInterval;if(Y!==void 0)V=setTimeout(()=>this.wake(),Y),V.unref?.();this.resume=()=>{clearTimeout(V),z()}})}retryDelay(){let z=Math.min(Math.max(0,this.claimFailures-1),30);return Math.min(this.config.pollInterval*2**z,i0)}wake(){this.woken=!0;let z=this.resume;this.resume=void 0,z?.()}get durable(){return!(this.driver instanceof i)}mayClaimHere(){return!this.application||n0()}lease(){return{visibilityTimeoutMs:this.config.visibilityTimeout}}execute(z){let V=`${z.id}:${z.attempt}`,Y=()=>this.run(z),Z=(this.application?W0.run(this.application,Y):Y()).catch(($)=>{console.error(`The queue could not record the outcome of ${z.name}.`,$)}).finally(()=>{this.inFlight.delete(V),this.wake()});this.inFlight.set(V,{job:z,done:Z}),this.heartbeat()}heartbeat(){let z=this.driver;if(!z.heartbeat||this.heartbeatTimer)return;this.heartbeatTimer=setInterval(()=>{if(this.inFlight.size===0){clearInterval(this.heartbeatTimer),this.heartbeatTimer=void 0;return}let V=[...this.inFlight.values()].map((Y)=>Y.job);z.heartbeat(V,this.lease()).catch((Y)=>{console.error("The queue could not extend its job leases.",Y)})},Math.max(1,Math.floor(this.config.visibilityTimeout/3))),this.heartbeatTimer.unref?.()}async run(z){let V=this.jobs[z.name];if(!V){let B=Date.now()-z.createdAt;if(this.durable&&B<this.config.unknownJobGrace){if(!this.releasedNames.has(z.name))this.releasedNames.add(z.name),console.error(`Left a queued "${z.name}" for another replica: nothing is registered here under that name. It is dead-lettered if no replica has run it within unknownJobGrace (${this.config.unknownJobGrace}ms) of its dispatch.`);await this.driver.release(z,{retryInMs:Math.round(this.config.pollInterval*(1+Math.random()))});return}console.error(`Dropped a queued job: nothing is registered under the name "${z.name}". If the class exists, it was not `+"discovered \u2014 check that it is under the queue slice's jobsDir "+"(app/jobs by default), or list it in app/config/queue.ts."),await this.driver.fail(z,{error:`No job is registered under the name "${z.name}".`,retryInMs:null});return}let Y;try{Y=new V}catch(B){console.error(`Dropped a queued ${z.name}: it could not be constructed.`,B),await this.driver.fail(z,{error:`The job could not be constructed: ${String(B)}`,retryInMs:null});return}let Z;try{Z=JSON.parse(z.args)}catch(B){console.error(`Dropped a queued ${z.name}: its arguments are not JSON.`,B),await this.driver.fail(z,{error:`The arguments are not JSON: ${String(B)}`,retryInMs:null});return}if(z.attempt>Math.max(1,Y.maxAttempts)){let B=Error(`${z.name} was claimed for attempt ${z.attempt} of ${Y.maxAttempts}: an earlier attempt never finished, most likely because the process running it exited. Dead-lettered without running it again.`);$0(`${z.name}.onDeadletter`,()=>Y.onDeadletter(B,...Z)),await this.driver.fail(z,{error:B.message,retryInMs:null}),await this.releaseUnique(Y,Z,z);return}if(Y.$claimed={...z},z.batchId!==void 0){if((await this.driver.findBatch?.(z.batchId,{progress:!1}))?.cancelledAt!=null){await this.driver.fail(z,{error:"Its batch was cancelled before it ran.",retryInMs:null,cancelled:!0});return}let K=this.batchHandle(z);Y.batch=K.batch,Y.$progress=K.progress}let $=await this.admit(Y,Z,z);if(!$)return;let X,H;try{H=await(Y.worker?c0(z.name,z.args):Y.run(...Z))}catch(B){X=B}finally{await $.done()}let G=Y.$outcome;if(X===void 0&&G?.kind==="release"){await this.driver.release(z,{retryInMs:Math.max(0,G.delayMs)});return}if(X===void 0&&G?.kind==="fail")X=G.error;let Q=G?.kind==="fail"?G.retry:!0;if(X===void 0)try{Y.onSuccess(H,...Z)}catch(B){X=B}if(X!==void 0){let B=String(X?.stack??X);if($0(`${z.name}.onFail`,()=>Y.onFail(X,...Z)),!Q||z.attempt>=Y.maxAttempts)$0(`${z.name}.onDeadletter`,()=>Y.onDeadletter(X,...Z)),await this.driver.fail(z,{error:B,retryInMs:null}),await this.releaseUnique(Y,Z,z);else await this.driver.fail(z,{error:B,retryInMs:s(Y.backoff,z.attempt)});return}await this.driver.complete(z),await this.releaseUnique(Y,Z,z)}batchHandle(z){let V=z.batchId,Y=this.driver;return{batch:{id:V,cancelled:async()=>(await Y.findBatch?.(V,{progress:!1}))?.cancelledAt!=null},progress:(Z)=>Y.reportProgress?.(z,Z)??Promise.resolve()}}async admit(z,V,Y){let Z=z.concurrency(...V),$=[z.throttle(...V)??[]].flat();if(!Z&&$.length===0)return{done:async()=>{}};let X=this.locks,H;if(Z&&Z.limit>0){let Q=this.config.visibilityTimeout;for(let B=0;B<Z.limit&&!H;B++)H=await X.acquire(`gemi:concurrency:${Z.key}:${B}`,{ttl:Q,renew:!0})??void 0;if(!H){await this.driver.release(Y,{retryInMs:Math.round(this.config.pollInterval*(1+Math.random()))});return}}let G=[];for(let Q of $){let B=`gemi:throttle:${Q.key}`,K=await X.store.hit(B,Q.limit,Q.window);if(!K.allowed){await Promise.all(G.map((A)=>X.store.refund(A))),await H?.release(),await this.driver.release(Y,{retryInMs:Math.max(1,K.resetInMs)});return}G.push(B)}return{done:async()=>{await H?.release().catch((Q)=>{console.error(`[gemi] Could not free a concurrency slot of ${Y.name}.`,Q)})}}}}function L0(z,V){return`gemi:job:${z}:${String(V)}`}function $0(z,V){try{V()}catch(Y){console.error(`${z} threw; the job's claim was ended anyway.`,Y)}}function s0(){return Bun.env.NODE_ENV==="production"}function n0(){if(!w0)return!1;if(r0())return!0;return process.env.ROOT_DIR!==void 0&&!a0()}function a0(z=process.env){return(z.GEMI_QUEUE_CLAIM??"").trim().toLowerCase()==="off"}var x0=Symbol.for("gemi.queue.worker");function iz(z=!0){globalThis[x0]=z}function r0(){return globalThis[x0]===!0}function t0(z,V){if(z==="memory")return new i;if(z==="database"||typeof z==="function"){if(!V&&(z==="database"||z.length>0))throw Error("The queue driver needs the application it belongs to, and this QueueManager was built without one. Pass { application }.");if(z==="database")return new z0(V.make(X0));return z(V)}if(typeof z==="string")throw Error(`Unknown queue driver "${z}". The queue slice's driver is "memory", "database", a QueueDriver, or a function returning one.`);return z}class S{static name="unset";worker=!1;maxAttempts=3;backoff=0;uniqueId(...z){return}uniqueFor=3600000;throttle(...z){return}concurrency(...z){return}release(z=0){this.$outcome={kind:"release",delayMs:z}}fail(z,V={}){this.$outcome={kind:"fail",error:z instanceof Error?z:Error(String(z)),retry:V.retry??!0}}batch=void 0;async progress(z){let V=E(z);await this.$progress?.(V)}$progress;$claimed;$outcome;run(...z){}onFail(z,...V){}onSuccess(z,...V){}onDeadletter(z,...V){}static dispatch(...z){if(this.name==="unset")throw Error("Cannot dispatch a job with no name");return b(h).push(this,JSON.stringify(z))}static dispatchBatch(z,V={}){if(this.name==="unset")throw Error("Cannot dispatch a job with no name");return b(h).pushBatch(this,z.map((Y)=>JSON.stringify(Y)),V)}static with(...z){if(this.name==="unset")throw Error("Cannot use a job with no name as a callback");return JSON.stringify(z),{name:this.name,args:z}}static findBatch(z){return b(h).findBatch(z)}static cancelBatch(z){return b(h).cancelBatch(z)}}var r=["completed","failed","cancelled"],o0=1000;class H0{queue;registry={};storeInstance;tickClass;reportedNames=new Set;constructor(z){this.queue=z}get workflows(){return this.registry}use(z){this.registry={};for(let V of z){if(V.name==="unset"||!V.name){console.error("A workflow class has no `static name`, so it was not registered. Add one.");continue}if(this.registry[V.name]){console.error(`Two workflows are named "${V.name}" \u2014 the first is registered `+"and this one is not. A workflow's name is its key in storage. Rename one.");continue}this.registry[V.name]=V}}get tickJob(){return this.tickClass??=e0(this),this.tickClass}get store(){if(!this.storeInstance){let z=this.queue.driver.workflowStore?.();if(!z||!this.queue.driver.enqueueBatch)throw Error("This queue's driver does not support workflows. The memory and database drivers do.");this.storeInstance=z}return this.storeInstance}start(z,V){if(z.name==="unset"||!z.name)throw Error("Cannot start a workflow with no name");let Y=this.store,Z={id:Bun.randomUUIDv7(),name:z.name,args:m(V,`The arguments of ${z.name}`)??"[]"},$=()=>this.queue.claimSoon(),X=Y.joinsTransaction?.()===!0;if(!X){if(C(()=>Y.create(Z).then($,(B)=>{console.error(`[gemi] The queue could not record the workflow ${z.name}, which was held until its transaction committed. The transaction stays committed; the workflow did not start.`,B)})))return Promise.resolve(Z.id)}let H=Y.create(Z),G=X&&C($);return H.then(()=>{if(!G)$();return Z.id})}async signal(z,V,Y){if(typeof V!=="string"||V.length===0||V.length>191)throw TypeError("A signal key is a string of 1 to 191 characters.");let Z=m(Y,`The payload of signal "${V}"`),$=await this.store.update(z,{key:V},({workflow:X,step:H,now:G})=>{if(r.includes(X.status)||X.status==="cancelling")return{result:!1};if(!H)return{result:!0,step:{workflowId:z,key:V,status:"signalled",attempt:0,output:Z,error:null,batchId:null,wakeAt:null,startedAt:null,finishedAt:G,createdAt:G,updatedAt:G}};if(H.status!=="waiting")return{result:!1};return{result:!0,step:{...H,status:"signalled",output:Z,wakeAt:H.wakeAt,finishedAt:G},tick:{delayMs:0}}});if($)this.queue.claimSoon();return $===!0}async cancel(z){let V=await this.store.update(z,{allSteps:!0},({workflow:Y,steps:Z})=>{if(r.includes(Y.status)||Y.status==="cancelling")return{result:!1};return{result:!0,workflow:{status:"cancelling"},cancelBatches:Z.filter(($)=>$.status==="batching"&&$.batchId!==null).map(($)=>$.batchId),tick:{delayMs:0}}});if(V)this.queue.claimSoon();return V===!0}async find(z){let V=await this.store.find(z);if(!V)return null;let{workflow:Y,steps:Z}=V,$=[];try{$=JSON.parse(Y.args)}catch{}return{id:Y.id,name:Y.name,status:Y.status,args:$,currentStep:Y.currentStep,progress:Y.progress,result:zz(Y.result),error:Y.error,steps:await Promise.all(Z.map(async(X)=>{let H={key:X.key,status:X.status,attempt:X.attempt,error:X.error,batchId:X.batchId,wakeAt:X.wakeAt,startedAt:X.startedAt,finishedAt:X.finishedAt};if(X.batchId===null)return H;let G=await this.queue.driver.findBatch?.(X.batchId);return G?{...H,progress:G.progress}:H})),createdAt:Y.createdAt,updatedAt:Y.updatedAt}}async tick(z,V){let Y=this.store,Z=V.$claimed,$=Z?`${Z.id}:${Z.attempt}`:`${crypto.randomUUID()}:1`,X=Math.max(1,this.queue.config.visibilityTimeout),H=await Y.acquire(z,$,X);if(H.kind!=="acquired")return;let{workflow:G}=H,Q=(J={})=>Y.update(z,{owner:$},()=>({...J,result:void 0,unlock:!0})).then(()=>this.queue.claimSoon()).catch((P)=>{if(!(P instanceof R))throw P});if(r.includes(G.status))return Q();let B=this.registry[G.name];if(!B)return this.unknown(G,V,Q);let K;try{K=JSON.parse(G.args)}catch(J){return Q({workflow:{status:"failed",error:`The arguments are not JSON: ${a(J)}`}})}let A=setInterval(()=>{Y.renew(z,$,X).catch((J)=>{console.error(`[gemi] Could not extend the hold on workflow ${z}.`,J)})},Math.max(1,Math.floor(X/3)));A.unref?.();let F=G.status==="cancelling",U=new Z0({workflowId:z,owner:$,store:Y,steps:H.steps,cancelling:F,findBatch:(J)=>this.queue.driver.findBatch?.(J,{progress:!1})??Promise.resolve(null),buildBatch:(J,P,N)=>this.queue.buildBatch(J,P.map((D)=>JSON.stringify(D)),{name:N.name,allowFailures:N.allowFailures,finally:{name:I,args:[z]}}),scheduled:()=>this.queue.claimSoon(),cancelCheckMs:o0});try{let J;try{let P=new B,N=await(F?P.onCancel(U,...K):P.run(U,...K));J=U.suspension?{kind:"suspended"}:{kind:"completed",result:F?null:m(N,`The result of ${G.name}`)}}catch(P){if(J=U.suspension||P instanceof g?{kind:"suspended"}:{kind:"failed",error:a(P)},P instanceof R)U.lost=!0}if(await U.settled(),U.lost)return;if(J.kind==="completed"&&U.suspension)J={kind:"suspended"};await Y.update(z,{owner:$},({workflow:P,now:N})=>this.finish(P,J,U,F,N)),this.queue.claimSoon()}catch(J){if(J instanceof R)return;throw J}finally{clearInterval(A)}}finish(z,V,Y,Z,$){let X={result:void 0,unlock:!0};if(z.status==="cancelling"&&!Z)return{...X,tick:{delayMs:0}};if(V.kind==="completed")return{...X,workflow:Z?{status:"cancelled",currentStep:null,wakeAt:null}:{status:"completed",result:V.result,progress:1,currentStep:null,wakeAt:null,error:null}};if(V.kind==="failed")return{...X,workflow:{status:Z?"cancelled":"failed",error:V.error,wakeAt:null}};let H=Y.suspension??{status:"waiting",wakes:[]},G={...X,workflow:{status:Z?"cancelling":H.status,currentStep:Y.current??z.currentStep}};if(H.wakes.length>0){let Q=Math.min(...H.wakes);if(!(z.wakeAt!==null&&z.wakeAt>$&&z.wakeAt<=Q))G.tick={delayMs:Math.max(0,Q-$)},G.workflow.wakeAt=Q}return G}async unknown(z,V,Y){let Z=Date.now()-z.createdAt;if(this.queue.durable&&Z<this.queue.config.unknownJobGrace){if(!this.reportedNames.has(z.name))this.reportedNames.add(z.name),console.error(`Left workflow "${z.name}" for another replica: nothing is registered here under that name.`);await Y(),V.release(Math.round(this.queue.config.pollInterval*(1+Math.random())));return}console.error(`Failed workflow ${z.id}: nothing is registered under the name "${z.name}". If the class exists, it was not discovered: check that it is under the queue slice's workflowsDir (app/workflows by default), or list it in app/config/queue.ts.`),await Y({workflow:{status:"failed",error:`No workflow is registered under the name "${z.name}".`}})}tickDeadLettered(z,V){console.error(`[gemi] The tick of workflow ${z} was dead-lettered.`,V),this.store.update(z,{},({workflow:Y})=>r.includes(Y.status)?{result:void 0}:{result:void 0,workflow:{status:"failed",error:`Its tick job was dead-lettered: ${V.message}`},unlock:!0}).catch(()=>{})}}function e0(z){return class extends S{static name=I;maxAttempts=20;backoff=[1000,5000,15000,30000,60000];async run(Y){await z.tick(Y,this)}onDeadletter(Y,Z){z.tickDeadLettered(Z,Y)}}}function zz(z){try{return _(z)}catch{return z}}
|
|
414
|
+
export{y as od,p as pd,o as qd,F0 as rd,z0 as sd,Nz as td,C0 as ud,V0 as vd,i as wd,I0 as xd,Y0 as yd,E0 as zd,O0 as Ad,Z0 as Bd,H0 as Cd,h as Dd,n0 as Ed,a0 as Fd,iz as Gd,r0 as Hd,S as Id};
|
|
415
415
|
|
|
416
|
-
//# debugId=
|
|
416
|
+
//# debugId=AE728C36454E390B64756E2164756E21
|