rivetkit 2.0.28 → 2.0.29

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.
Files changed (93) hide show
  1. package/dist/tsup/actor/errors.cjs +2 -2
  2. package/dist/tsup/actor/errors.js +1 -1
  3. package/dist/tsup/{chunk-EJXISR3H.js → chunk-2LOXTB3G.js} +3 -3
  4. package/dist/tsup/{chunk-Y2AKEZRY.cjs → chunk-3RJG3PC3.cjs} +3 -3
  5. package/dist/tsup/{chunk-Y2AKEZRY.cjs.map → chunk-3RJG3PC3.cjs.map} +1 -1
  6. package/dist/tsup/{chunk-DATRTJVZ.js → chunk-5IE76QRF.js} +3 -3
  7. package/dist/tsup/{chunk-NR2N4UA2.cjs → chunk-72P7NQS4.cjs} +10 -10
  8. package/dist/tsup/{chunk-NR2N4UA2.cjs.map → chunk-72P7NQS4.cjs.map} +1 -1
  9. package/dist/tsup/{chunk-3ZC6SBX6.cjs → chunk-7DSWCOGX.cjs} +183 -182
  10. package/dist/tsup/chunk-7DSWCOGX.cjs.map +1 -0
  11. package/dist/tsup/{chunk-M54KFQQP.cjs → chunk-7XZX3T4D.cjs} +8 -8
  12. package/dist/tsup/{chunk-M54KFQQP.cjs.map → chunk-7XZX3T4D.cjs.map} +1 -1
  13. package/dist/tsup/{chunk-AE7BB3M2.js → chunk-EWQE7L3V.js} +2 -2
  14. package/dist/tsup/{chunk-KXSSOVFA.js → chunk-FBPZAU3N.js} +80 -15
  15. package/dist/tsup/chunk-FBPZAU3N.js.map +1 -0
  16. package/dist/tsup/{chunk-ZL3SUOIM.js → chunk-H27UUFLD.js} +9 -9
  17. package/dist/tsup/{chunk-Y5LN2XRH.cjs → chunk-HK6QNZX3.cjs} +8 -8
  18. package/dist/tsup/{chunk-Y5LN2XRH.cjs.map → chunk-HK6QNZX3.cjs.map} +1 -1
  19. package/dist/tsup/{chunk-ILK4JEMF.js → chunk-KMOA3GQ2.js} +2 -2
  20. package/dist/tsup/{chunk-XJMYGATE.cjs → chunk-MAQSR26X.cjs} +8 -3
  21. package/dist/tsup/chunk-MAQSR26X.cjs.map +1 -0
  22. package/dist/tsup/{chunk-CJLXW36F.cjs → chunk-MZ3SRIPM.cjs} +286 -221
  23. package/dist/tsup/chunk-MZ3SRIPM.cjs.map +1 -0
  24. package/dist/tsup/{chunk-NQZ643FB.cjs → chunk-MZCRC64W.cjs} +17 -17
  25. package/dist/tsup/{chunk-NQZ643FB.cjs.map → chunk-MZCRC64W.cjs.map} +1 -1
  26. package/dist/tsup/{chunk-LQOCWGP6.js → chunk-P2RZJPYI.js} +1 -1
  27. package/dist/tsup/{chunk-IDYDUETM.js → chunk-POJ4HHIO.js} +3 -3
  28. package/dist/tsup/chunk-POJ4HHIO.js.map +1 -0
  29. package/dist/tsup/{chunk-JALGQWHW.cjs → chunk-QB7FJ2OK.cjs} +15 -15
  30. package/dist/tsup/{chunk-JALGQWHW.cjs.map → chunk-QB7FJ2OK.cjs.map} +1 -1
  31. package/dist/tsup/{chunk-VQRYS6VW.cjs → chunk-UBBTSSAP.cjs} +3 -3
  32. package/dist/tsup/{chunk-VQRYS6VW.cjs.map → chunk-UBBTSSAP.cjs.map} +1 -1
  33. package/dist/tsup/{chunk-YW2E3UPH.cjs → chunk-UENID7AK.cjs} +6 -6
  34. package/dist/tsup/chunk-UENID7AK.cjs.map +1 -0
  35. package/dist/tsup/{chunk-7IAEY5UZ.js → chunk-UJ6ETM45.js} +2 -2
  36. package/dist/tsup/{chunk-S5URQ3CI.js → chunk-WXLDDJCI.js} +3 -3
  37. package/dist/tsup/{chunk-S5URQ3CI.js.map → chunk-WXLDDJCI.js.map} +1 -1
  38. package/dist/tsup/{chunk-AHPMXTSB.js → chunk-YPHTAWZP.js} +16 -16
  39. package/dist/tsup/chunk-YPHTAWZP.js.map +1 -0
  40. package/dist/tsup/client/mod.cjs +9 -9
  41. package/dist/tsup/client/mod.d.cts +2 -2
  42. package/dist/tsup/client/mod.d.ts +2 -2
  43. package/dist/tsup/client/mod.js +8 -8
  44. package/dist/tsup/common/log.cjs +3 -3
  45. package/dist/tsup/common/log.js +2 -2
  46. package/dist/tsup/common/websocket.cjs +4 -4
  47. package/dist/tsup/common/websocket.js +3 -3
  48. package/dist/tsup/{config-DxlmiJS1.d.cts → config-BEu-kmmR.d.cts} +32 -1
  49. package/dist/tsup/{config-CcMdKDv9.d.ts → config-DELCUYts.d.ts} +32 -1
  50. package/dist/tsup/driver-helpers/mod.cjs +5 -5
  51. package/dist/tsup/driver-helpers/mod.d.cts +1 -1
  52. package/dist/tsup/driver-helpers/mod.d.ts +1 -1
  53. package/dist/tsup/driver-helpers/mod.js +4 -4
  54. package/dist/tsup/driver-test-suite/mod.cjs +192 -74
  55. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -1
  56. package/dist/tsup/driver-test-suite/mod.d.cts +1 -1
  57. package/dist/tsup/driver-test-suite/mod.d.ts +1 -1
  58. package/dist/tsup/driver-test-suite/mod.js +135 -17
  59. package/dist/tsup/driver-test-suite/mod.js.map +1 -1
  60. package/dist/tsup/inspector/mod.cjs +6 -6
  61. package/dist/tsup/inspector/mod.d.cts +2 -2
  62. package/dist/tsup/inspector/mod.d.ts +2 -2
  63. package/dist/tsup/inspector/mod.js +5 -5
  64. package/dist/tsup/mod.cjs +10 -10
  65. package/dist/tsup/mod.cjs.map +1 -1
  66. package/dist/tsup/mod.d.cts +2 -2
  67. package/dist/tsup/mod.d.ts +2 -2
  68. package/dist/tsup/mod.js +9 -9
  69. package/dist/tsup/test/mod.cjs +12 -12
  70. package/dist/tsup/test/mod.d.cts +1 -1
  71. package/dist/tsup/test/mod.d.ts +1 -1
  72. package/dist/tsup/test/mod.js +11 -11
  73. package/dist/tsup/utils.cjs +3 -3
  74. package/dist/tsup/utils.js +2 -2
  75. package/package.json +2 -2
  76. package/src/actor/mod.ts +2 -0
  77. package/src/client/actor-conn.ts +87 -0
  78. package/src/client/mod.ts +5 -1
  79. package/src/driver-test-suite/tests/actor-conn.ts +199 -0
  80. package/dist/tsup/chunk-3ZC6SBX6.cjs.map +0 -1
  81. package/dist/tsup/chunk-AHPMXTSB.js.map +0 -1
  82. package/dist/tsup/chunk-CJLXW36F.cjs.map +0 -1
  83. package/dist/tsup/chunk-IDYDUETM.js.map +0 -1
  84. package/dist/tsup/chunk-KXSSOVFA.js.map +0 -1
  85. package/dist/tsup/chunk-XJMYGATE.cjs.map +0 -1
  86. package/dist/tsup/chunk-YW2E3UPH.cjs.map +0 -1
  87. /package/dist/tsup/{chunk-EJXISR3H.js.map → chunk-2LOXTB3G.js.map} +0 -0
  88. /package/dist/tsup/{chunk-DATRTJVZ.js.map → chunk-5IE76QRF.js.map} +0 -0
  89. /package/dist/tsup/{chunk-AE7BB3M2.js.map → chunk-EWQE7L3V.js.map} +0 -0
  90. /package/dist/tsup/{chunk-ZL3SUOIM.js.map → chunk-H27UUFLD.js.map} +0 -0
  91. /package/dist/tsup/{chunk-ILK4JEMF.js.map → chunk-KMOA3GQ2.js.map} +0 -0
  92. /package/dist/tsup/{chunk-LQOCWGP6.js.map → chunk-P2RZJPYI.js.map} +0 -0
  93. /package/dist/tsup/{chunk-7IAEY5UZ.js.map → chunk-UJ6ETM45.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/rivet/rivet/rivetkit-typescript/packages/rivetkit/dist/tsup/chunk-7DSWCOGX.cjs","../../src/actor/config.ts","../../src/actor/router.ts","../../src/actor/router-endpoints.ts","../../src/actor/conn/drivers/raw-request.ts","../../src/common/router.ts","../../src/registry/config.ts","../../src/actor/router-websocket-endpoints.ts","../../src/actor/conn/drivers/raw-websocket.ts","../../src/actor/conn/drivers/websocket.ts","../../src/actor/mod.ts","../../src/common/inline-websocket-adapter.ts","../../src/drivers/engine/actor-driver.ts","../../src/drivers/engine/log.ts","../../src/drivers/engine/mod.ts","../../src/utils/node.ts","../../src/drivers/file-system/actor.ts","../../src/drivers/file-system/global-state.ts","../../src/schemas/file-system-driver/versioned.ts","../schemas/file-system-driver/v1.ts","../schemas/file-system-driver/v2.ts","../schemas/file-system-driver/v3.ts","../../src/drivers/file-system/log.ts","../../src/drivers/file-system/utils.ts","../../src/drivers/file-system/manager.ts","../../src/inspector/manager.ts","../../src/drivers/file-system/mod.ts","../../src/registry/mod.ts","../../src/drivers/default.ts","../../src/engine-process/log.ts","../../src/engine-process/mod.ts","../../src/manager/router.ts","../../src/common/cors.ts","../../src/manager-api/actors.ts","../../src/manager-api/common.ts","../../src/manager/log.ts","../../src/manager/gateway.ts","../../src/manager/router-schema.ts","../../src/registry/log.ts","../../src/registry/serve.ts"],"names":["bare","actor"],"mappings":"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","file":"/home/runner/work/rivet/rivet/rivetkit-typescript/packages/rivetkit/dist/tsup/chunk-7DSWCOGX.cjs","sourcesContent":[null,"import { z } from \"zod\";\nimport type { UniversalWebSocket } from \"@/common/websocket-interface\";\nimport type { Conn } from \"./conn/mod\";\nimport type { ActionContext } from \"./contexts/action\";\nimport type { ActorContext } from \"./contexts/actor\";\nimport type { CreateConnStateContext } from \"./contexts/create-conn-state\";\nimport type { OnBeforeConnectContext } from \"./contexts/on-before-connect\";\nimport type { OnConnectContext } from \"./contexts/on-connect\";\nimport type { RequestContext } from \"./contexts/request\";\nimport type { WebSocketContext } from \"./contexts/websocket\";\nimport type { AnyDatabaseProvider } from \"./database\";\n\nexport type InitContext = ActorContext<\n\tundefined,\n\tundefined,\n\tundefined,\n\tundefined,\n\tundefined,\n\tundefined\n>;\n\nexport interface ActorTypes<\n\tTState,\n\tTConnParams,\n\tTConnState,\n\tTVars,\n\tTInput,\n\tTDatabase extends AnyDatabaseProvider,\n> {\n\tstate?: TState;\n\tconnParams?: TConnParams;\n\tconnState?: TConnState;\n\tvars?: TVars;\n\tinput?: TInput;\n\tdatabase?: TDatabase;\n}\n\n// Helper for validating function types - accepts generic for specific function signatures\nconst zFunction = <T extends (...args: any[]) => any = (...args: unknown[]) => unknown>() =>\n\tz.custom<T>((val) => typeof val === \"function\");\n\n// This schema is used to validate the input at runtime. The generic types are defined below in `ActorConfig`.\n//\n// We don't use Zod generics with `z.custom` because:\n// (a) there seems to be a weird bug in either Zod, tsup, or TSC that causese external packages to have different types from `z.infer` than from within the same package and\n// (b) it makes the type definitions incredibly difficult to read as opposed to vanilla TypeScript.\nexport const ActorConfigSchema = z\n\t.object({\n\t\tonCreate: zFunction().optional(),\n\t\tonDestroy: zFunction().optional(),\n\t\tonWake: zFunction().optional(),\n\t\tonSleep: zFunction().optional(),\n\t\tonStateChange: zFunction().optional(),\n\t\tonBeforeConnect: zFunction().optional(),\n\t\tonConnect: zFunction().optional(),\n\t\tonDisconnect: zFunction().optional(),\n\t\tonBeforeActionResponse: zFunction().optional(),\n\t\tonRequest: zFunction().optional(),\n\t\tonWebSocket: zFunction().optional(),\n\t\tactions: z.record(z.string(), zFunction()).default(() => ({})),\n\t\tstate: z.any().optional(),\n\t\tcreateState: zFunction().optional(),\n\t\tconnState: z.any().optional(),\n\t\tcreateConnState: zFunction().optional(),\n\t\tvars: z.any().optional(),\n\t\tdb: z.any().optional(),\n\t\tcreateVars: zFunction().optional(),\n\t\toptions: z\n\t\t\t.object({\n\t\t\t\tcreateVarsTimeout: z.number().positive().default(5000),\n\t\t\t\tcreateConnStateTimeout: z.number().positive().default(5000),\n\t\t\t\tonConnectTimeout: z.number().positive().default(5000),\n\t\t\t\t// This must be less than ACTOR_STOP_THRESHOLD_MS\n\t\t\t\tonSleepTimeout: z.number().positive().default(5000),\n\t\t\t\tonDestroyTimeout: z.number().positive().default(5000),\n\t\t\t\tstateSaveInterval: z.number().positive().default(10_000),\n\t\t\t\tactionTimeout: z.number().positive().default(60_000),\n\t\t\t\t// Max time to wait for waitUntil background promises during shutdown\n\t\t\t\twaitUntilTimeout: z.number().positive().default(15_000),\n\t\t\t\tconnectionLivenessTimeout: z.number().positive().default(2500),\n\t\t\t\tconnectionLivenessInterval: z.number().positive().default(5000),\n\t\t\t\tnoSleep: z.boolean().default(false),\n\t\t\t\tsleepTimeout: z.number().positive().default(30_000),\n\t\t\t\t/**\n\t\t\t\t * Can hibernate WebSockets for onWebSocket.\n\t\t\t\t *\n\t\t\t\t * WebSockets using actions/events are hibernatable by default.\n\t\t\t\t *\n\t\t\t\t * @experimental\n\t\t\t\t **/\n\t\t\t\tcanHibernateWebSocket: z\n\t\t\t\t\t.union([\n\t\t\t\t\t\tz.boolean(),\n\t\t\t\t\t\tzFunction<(request: Request) => boolean>(),\n\t\t\t\t\t])\n\t\t\t\t\t.default(false),\n\t\t\t})\n\t\t\t.strict()\n\t\t\t.prefault(() => ({})),\n\t})\n\t.strict()\n\t.refine(\n\t\t(data) => !(data.state !== undefined && data.createState !== undefined),\n\t\t{\n\t\t\tmessage: \"Cannot define both 'state' and 'createState'\",\n\t\t\tpath: [\"state\"],\n\t\t},\n\t)\n\t.refine(\n\t\t(data) =>\n\t\t\t!(\n\t\t\t\tdata.connState !== undefined &&\n\t\t\t\tdata.createConnState !== undefined\n\t\t\t),\n\t\t{\n\t\t\tmessage: \"Cannot define both 'connState' and 'createConnState'\",\n\t\t\tpath: [\"connState\"],\n\t\t},\n\t)\n\t.refine(\n\t\t(data) => !(data.vars !== undefined && data.createVars !== undefined),\n\t\t{\n\t\t\tmessage: \"Cannot define both 'vars' and 'createVars'\",\n\t\t\tpath: [\"vars\"],\n\t\t},\n\t);\n\n// Creates state config\n//\n// This must have only one or the other or else TState will not be able to be inferred\n//\n// Data returned from this handler will be available on `c.state`.\ntype CreateState<TState, TConnParams, TConnState, TVars, TInput, TDatabase> =\n\t| { state: TState }\n\t| {\n\t\t\tcreateState: (\n\t\t\t\tc: InitContext,\n\t\t\t\tinput: TInput,\n\t\t\t) => TState | Promise<TState>;\n\t }\n\t| Record<never, never>;\n\n// Creates connection state config\n//\n// This must have only one or the other or else TState will not be able to be inferred\n//\n// Data returned from this handler will be available on `c.conn.state`.\ntype CreateConnState<\n\tTState,\n\tTConnParams,\n\tTConnState,\n\tTVars,\n\tTInput,\n\tTDatabase extends AnyDatabaseProvider,\n> =\n\t| { connState: TConnState }\n\t| {\n\t\t\tcreateConnState: (\n\t\t\t\tc: CreateConnStateContext<TState, TVars, TInput, TDatabase>,\n\t\t\t\tparams: TConnParams,\n\t\t\t) => TConnState | Promise<TConnState>;\n\t }\n\t| Record<never, never>;\n\n// Creates vars config\n//\n// This must have only one or the other or else TState will not be able to be inferred\n/**\n * @experimental\n */\ntype CreateVars<TState, TConnParams, TConnState, TVars, TInput, TDatabase> =\n\t| {\n\t\t\t/**\n\t\t\t * @experimental\n\t\t\t */\n\t\t\tvars: TVars;\n\t }\n\t| {\n\t\t\t/**\n\t\t\t * @experimental\n\t\t\t */\n\t\t\tcreateVars: (\n\t\t\t\tc: InitContext,\n\t\t\t\tdriverCtx: any,\n\t\t\t) => TVars | Promise<TVars>;\n\t }\n\t| Record<never, never>;\n\nexport interface Actions<\n\tTState,\n\tTConnParams,\n\tTConnState,\n\tTVars,\n\tTInput,\n\tTDatabase extends AnyDatabaseProvider,\n> {\n\t[Action: string]: (\n\t\tc: ActionContext<\n\t\t\tTState,\n\t\t\tTConnParams,\n\t\t\tTConnState,\n\t\t\tTVars,\n\t\t\tTInput,\n\t\t\tTDatabase\n\t\t>,\n\t\t...args: any[]\n\t) => any;\n}\n\n//export type ActorConfig<TState, TConnParams, TConnState, TVars, TInput, TAuthData> = BaseActorConfig<TState, TConnParams, TConnState, TVars, TInput, TAuthData> &\n//\tActorConfigLifecycle<TState, TConnParams, TConnState, TVars, TInput, TAuthData> &\n//\tCreateState<TState, TConnParams, TConnState, TVars, TInput, TAuthData> &\n//\tCreateConnState<TState, TConnParams, TConnState, TVars, TInput, TAuthData>;\n\n/**\n * @experimental\n */\nexport type AuthIntent = \"get\" | \"create\" | \"connect\" | \"action\" | \"message\";\n\ninterface BaseActorConfig<\n\tTState,\n\tTConnParams,\n\tTConnState,\n\tTVars,\n\tTInput,\n\tTDatabase extends AnyDatabaseProvider,\n\tTActions extends Actions<\n\t\tTState,\n\t\tTConnParams,\n\t\tTConnState,\n\t\tTVars,\n\t\tTInput,\n\t\tTDatabase\n\t>,\n> {\n\t/**\n\t * Called when the actor is first initialized.\n\t *\n\t * Use this hook to initialize your actor's state.\n\t * This is called before any other lifecycle hooks.\n\t */\n\tonCreate?: (\n\t\tc: ActorContext<\n\t\t\tTState,\n\t\t\tTConnParams,\n\t\t\tTConnState,\n\t\t\tTVars,\n\t\t\tTInput,\n\t\t\tTDatabase\n\t\t>,\n\t\tinput: TInput,\n\t) => void | Promise<void>;\n\n\t/**\n\t * Called when the actor is destroyed.\n\t */\n\tonDestroy?: (\n\t\tc: ActorContext<\n\t\t\tTState,\n\t\t\tTConnParams,\n\t\t\tTConnState,\n\t\t\tTVars,\n\t\t\tTInput,\n\t\t\tTDatabase\n\t\t>,\n\t) => void | Promise<void>;\n\n\t/**\n\t * Called when the actor is started and ready to receive connections and action.\n\t *\n\t * Use this hook to initialize resources needed for the actor's operation\n\t * (timers, external connections, etc.)\n\t *\n\t * @returns Void or a Promise that resolves when startup is complete\n\t */\n\tonWake?: (\n\t\tc: ActorContext<\n\t\t\tTState,\n\t\t\tTConnParams,\n\t\t\tTConnState,\n\t\t\tTVars,\n\t\t\tTInput,\n\t\t\tTDatabase\n\t\t>,\n\t) => void | Promise<void>;\n\n\t/**\n\t * Called when the actor is stopping or sleeping.\n\t *\n\t * Use this hook to clean up resources, save state, or perform\n\t * any shutdown operations before the actor sleeps or stops.\n\t *\n\t * Not supported on all platforms.\n\t *\n\t * @returns Void or a Promise that resolves when shutdown is complete\n\t */\n\tonSleep?: (\n\t\tc: ActorContext<\n\t\t\tTState,\n\t\t\tTConnParams,\n\t\t\tTConnState,\n\t\t\tTVars,\n\t\t\tTInput,\n\t\t\tTDatabase\n\t\t>,\n\t) => void | Promise<void>;\n\n\t/**\n\t * Called when the actor's state changes.\n\t *\n\t * Use this hook to react to state changes, such as updating\n\t * external systems or triggering events.\n\t *\n\t * State changes made within this hook will NOT trigger\n\t * another onStateChange call, preventing infinite recursion.\n\t *\n\t * @param newState The updated state\n\t */\n\tonStateChange?: (\n\t\tc: ActorContext<\n\t\t\tTState,\n\t\t\tTConnParams,\n\t\t\tTConnState,\n\t\t\tTVars,\n\t\t\tTInput,\n\t\t\tTDatabase\n\t\t>,\n\t\tnewState: TState,\n\t) => void;\n\n\t/**\n\t * Called before a client connects to the actor.\n\t *\n\t * Use this hook to determine if a connection should be accepted\n\t * and to initialize connection-specific state.\n\t *\n\t * @param opts Connection parameters including client-provided data\n\t * @returns The initial connection state or a Promise that resolves to it\n\t * @throws Throw an error to reject the connection\n\t */\n\tonBeforeConnect?: (\n\t\tc: OnBeforeConnectContext<TState, TVars, TInput, TDatabase>,\n\t\tparams: TConnParams,\n\t) => void | Promise<void>;\n\n\t/**\n\t * Called when a client successfully connects to the actor.\n\t *\n\t * Use this hook to perform actions when a connection is established,\n\t * such as sending initial data or updating the actor's state.\n\t *\n\t * @param conn The connection object\n\t * @returns Void or a Promise that resolves when connection handling is complete\n\t */\n\tonConnect?: (\n\t\tc: OnConnectContext<\n\t\t\tTState,\n\t\t\tTConnParams,\n\t\t\tTConnState,\n\t\t\tTVars,\n\t\t\tTInput,\n\t\t\tTDatabase\n\t\t>,\n\t\tconn: Conn<TState, TConnParams, TConnState, TVars, TInput, TDatabase>,\n\t) => void | Promise<void>;\n\n\t/**\n\t * Called when a client disconnects from the actor.\n\t *\n\t * Use this hook to clean up resources associated with the connection\n\t * or update the actor's state.\n\t *\n\t * @param conn The connection that is being closed\n\t * @returns Void or a Promise that resolves when disconnect handling is complete\n\t */\n\tonDisconnect?: (\n\t\tc: ActorContext<\n\t\t\tTState,\n\t\t\tTConnParams,\n\t\t\tTConnState,\n\t\t\tTVars,\n\t\t\tTInput,\n\t\t\tTDatabase\n\t\t>,\n\t\tconn: Conn<TState, TConnParams, TConnState, TVars, TInput, TDatabase>,\n\t) => void | Promise<void>;\n\n\t/**\n\t * Called before sending an action response to the client.\n\t *\n\t * Use this hook to modify or transform the output of an action before it's sent\n\t * to the client. This is useful for formatting responses, adding metadata,\n\t * or applying transformations to the output.\n\t *\n\t * @param name The name of the action that was called\n\t * @param args The arguments that were passed to the action\n\t * @param output The output that will be sent to the client\n\t * @returns The modified output to send to the client\n\t */\n\tonBeforeActionResponse?: <Out>(\n\t\tc: ActorContext<\n\t\t\tTState,\n\t\t\tTConnParams,\n\t\t\tTConnState,\n\t\t\tTVars,\n\t\t\tTInput,\n\t\t\tTDatabase\n\t\t>,\n\t\tname: string,\n\t\targs: unknown[],\n\t\toutput: Out,\n\t) => Out | Promise<Out>;\n\n\t/**\n\t * Called when a raw HTTP request is made to the actor.\n\t *\n\t * This handler receives raw HTTP requests made to `/actors/{actorName}/http/*` endpoints.\n\t * Use this hook to handle custom HTTP patterns, REST APIs, or other HTTP-based protocols.\n\t *\n\t * @param c The request context with access to the connection\n\t * @param request The raw HTTP request object\n\t * @param opts Additional options\n\t * @returns A Response object to send back, or void to continue with default routing\n\t */\n\tonRequest?: (\n\t\tc: RequestContext<\n\t\t\tTState,\n\t\t\tTConnParams,\n\t\t\tTConnState,\n\t\t\tTVars,\n\t\t\tTInput,\n\t\t\tTDatabase\n\t\t>,\n\t\trequest: Request,\n\t) => Response | Promise<Response>;\n\n\t/**\n\t * Called when a raw WebSocket connection is established to the actor.\n\t *\n\t * This handler receives WebSocket connections made to `/actors/{actorName}/websocket/*` endpoints.\n\t * Use this hook to handle custom WebSocket protocols, binary streams, or other WebSocket-based communication.\n\t *\n\t * @param c The WebSocket context with access to the connection\n\t * @param websocket The raw WebSocket connection\n\t * @param opts Additional options including the original HTTP upgrade request\n\t */\n\tonWebSocket?: (\n\t\tc: WebSocketContext<\n\t\t\tTState,\n\t\t\tTConnParams,\n\t\t\tTConnState,\n\t\t\tTVars,\n\t\t\tTInput,\n\t\t\tTDatabase\n\t\t>,\n\t\twebsocket: UniversalWebSocket,\n\t) => void | Promise<void>;\n\n\tactions: TActions;\n}\n\ntype ActorDatabaseConfig<TDatabase extends AnyDatabaseProvider> =\n\t| {\n\t\t\t/**\n\t\t\t * @experimental\n\t\t\t */\n\t\t\tdb: TDatabase;\n\t }\n\t| Record<never, never>;\n\n// 1. Infer schema\n// 2. Omit keys that we'll manually define (because of generics)\n// 3. Define our own types that have generic constraints\nexport type ActorConfig<\n\tTState,\n\tTConnParams,\n\tTConnState,\n\tTVars,\n\tTInput,\n\tTDatabase extends AnyDatabaseProvider,\n> = Omit<\n\tz.infer<typeof ActorConfigSchema>,\n\t| \"actions\"\n\t| \"onCreate\"\n\t| \"onDestroy\"\n\t| \"onWake\"\n\t| \"onStateChange\"\n\t| \"onBeforeConnect\"\n\t| \"onConnect\"\n\t| \"onDisconnect\"\n\t| \"onBeforeActionResponse\"\n\t| \"onRequest\"\n\t| \"onWebSocket\"\n\t| \"state\"\n\t| \"createState\"\n\t| \"connState\"\n\t| \"createConnState\"\n\t| \"vars\"\n\t| \"createVars\"\n\t| \"db\"\n> &\n\tBaseActorConfig<\n\t\tTState,\n\t\tTConnParams,\n\t\tTConnState,\n\t\tTVars,\n\t\tTInput,\n\t\tTDatabase,\n\t\tActions<TState, TConnParams, TConnState, TVars, TInput, TDatabase>\n\t> &\n\tCreateState<TState, TConnParams, TConnState, TVars, TInput, TDatabase> &\n\tCreateConnState<TState, TConnParams, TConnState, TVars, TInput, TDatabase> &\n\tCreateVars<TState, TConnParams, TConnState, TVars, TInput, TDatabase> &\n\tActorDatabaseConfig<TDatabase>;\n\n// See description on `ActorConfig`\nexport type ActorConfigInput<\n\tTState = undefined,\n\tTConnParams = undefined,\n\tTConnState = undefined,\n\tTVars = undefined,\n\tTInput = undefined,\n\tTDatabase extends AnyDatabaseProvider = undefined,\n\tTActions extends Actions<\n\t\tTState,\n\t\tTConnParams,\n\t\tTConnState,\n\t\tTVars,\n\t\tTInput,\n\t\tTDatabase\n\t> = Record<never, never>,\n> = {\n\ttypes?: ActorTypes<\n\t\tTState,\n\t\tTConnParams,\n\t\tTConnState,\n\t\tTVars,\n\t\tTInput,\n\t\tTDatabase\n\t>;\n} & Omit<\n\tz.input<typeof ActorConfigSchema>,\n\t| \"actions\"\n\t| \"onCreate\"\n\t| \"onDestroy\"\n\t| \"onWake\"\n\t| \"onSleep\"\n\t| \"onStateChange\"\n\t| \"onBeforeConnect\"\n\t| \"onConnect\"\n\t| \"onDisconnect\"\n\t| \"onBeforeActionResponse\"\n\t| \"onRequest\"\n\t| \"onWebSocket\"\n\t| \"state\"\n\t| \"createState\"\n\t| \"connState\"\n\t| \"createConnState\"\n\t| \"vars\"\n\t| \"createVars\"\n\t| \"db\"\n> &\n\tBaseActorConfig<\n\t\tTState,\n\t\tTConnParams,\n\t\tTConnState,\n\t\tTVars,\n\t\tTInput,\n\t\tTDatabase,\n\t\tTActions\n\t> &\n\tCreateState<TState, TConnParams, TConnState, TVars, TInput, TDatabase> &\n\tCreateConnState<TState, TConnParams, TConnState, TVars, TInput, TDatabase> &\n\tCreateVars<TState, TConnParams, TConnState, TVars, TInput, TDatabase> &\n\tActorDatabaseConfig<TDatabase>;\n\n// For testing type definitions:\nexport function test<\n\tTState,\n\tTConnParams,\n\tTConnState,\n\tTVars,\n\tTInput,\n\tTDatabase extends AnyDatabaseProvider,\n\tTActions extends Actions<\n\t\tTState,\n\t\tTConnParams,\n\t\tTConnState,\n\t\tTVars,\n\t\tTInput,\n\t\tTDatabase\n\t>,\n>(\n\tinput: ActorConfigInput<\n\t\tTState,\n\t\tTConnParams,\n\t\tTConnState,\n\t\tTVars,\n\t\tTInput,\n\t\tTDatabase,\n\t\tTActions\n\t>,\n): ActorConfig<TState, TConnParams, TConnState, TVars, TInput, TDatabase> {\n\tconst config = ActorConfigSchema.parse(input) as ActorConfig<\n\t\tTState,\n\t\tTConnParams,\n\t\tTConnState,\n\t\tTVars,\n\t\tTInput,\n\t\tTDatabase\n\t>;\n\treturn config;\n}\n","import { Hono } from \"hono\";\nimport invariant from \"invariant\";\nimport {\n\ttype ActionOpts,\n\ttype ActionOutput,\n\ttype ConnsMessageOpts,\n\thandleAction,\n\thandleRawRequest,\n} from \"@/actor/router-endpoints\";\nimport {\n\tPATH_CONNECT,\n\tPATH_INSPECTOR_CONNECT,\n\tPATH_WEBSOCKET_PREFIX,\n} from \"@/common/actor-router-consts\";\nimport {\n\thandleRouteError,\n\thandleRouteNotFound,\n\tloggerMiddleware,\n} from \"@/common/router\";\nimport { noopNext } from \"@/common/utils\";\nimport {\n\ttype ActorInspectorRouterEnv,\n\tcreateActorInspectorRouter,\n} from \"@/inspector/actor\";\nimport { isInspectorEnabled, secureInspector } from \"@/inspector/utils\";\nimport type { RunnerConfig } from \"@/registry/run-config\";\nimport { CONN_DRIVER_SYMBOL } from \"./conn/mod\";\nimport type { ActorDriver } from \"./driver\";\nimport { loggerWithoutContext } from \"./log\";\nimport {\n\tparseWebSocketProtocols,\n\trouteWebSocket,\n} from \"./router-websocket-endpoints\";\n\nexport type { ActionOpts, ActionOutput, ConnsMessageOpts };\n\ninterface ActorRouterBindings {\n\tactorId: string;\n}\n\nexport type ActorRouter = Hono<{ Bindings: ActorRouterBindings }>;\n\n/**\n * Creates a router that runs on the partitioned instance.\n */\nexport function createActorRouter(\n\trunConfig: RunnerConfig,\n\tactorDriver: ActorDriver,\n\tisTest: boolean,\n): ActorRouter {\n\tconst router = new Hono<{ Bindings: ActorRouterBindings }>({\n\t\tstrict: false,\n\t});\n\n\trouter.use(\"*\", loggerMiddleware(loggerWithoutContext()));\n\n\t// Track all HTTP requests to prevent actor from sleeping during active requests\n\trouter.use(\"*\", async (c, next) => {\n\t\tconst actor = await actorDriver.loadActor(c.env.actorId);\n\t\tactor.beginHonoHttpRequest();\n\t\ttry {\n\t\t\tawait next();\n\t\t} finally {\n\t\t\tactor.endHonoHttpRequest();\n\t\t}\n\t});\n\n\trouter.get(\"/\", (c) => {\n\t\treturn c.text(\n\t\t\t\"This is an RivetKit actor.\\n\\nLearn more at https://rivetkit.org\",\n\t\t);\n\t});\n\n\trouter.get(\"/health\", (c) => {\n\t\treturn c.text(\"ok\");\n\t});\n\n\tif (isTest) {\n\t\t// Test endpoint to force disconnect a connection non-cleanly\n\t\trouter.post(\"/.test/force-disconnect\", async (c) => {\n\t\t\tconst connId = c.req.query(\"conn\");\n\n\t\t\tif (!connId) {\n\t\t\t\treturn c.text(\"Missing conn query parameter\", 400);\n\t\t\t}\n\n\t\t\tconst actor = await actorDriver.loadActor(c.env.actorId);\n\t\t\tconst conn = actor.connectionManager.getConnForId(connId);\n\n\t\t\tif (!conn) {\n\t\t\t\treturn c.text(`Connection not found: ${connId}`, 404);\n\t\t\t}\n\n\t\t\t// Force close the connection without clean shutdown\n\t\t\tif (conn[CONN_DRIVER_SYMBOL]?.terminate) {\n\t\t\t\tconn[CONN_DRIVER_SYMBOL].terminate(actor, conn);\n\t\t\t}\n\n\t\t\treturn c.json({ success: true });\n\t\t});\n\t}\n\n\t// Route all WebSocket paths using the same handler\n\t//\n\t// All WebSockets use a separate underlying router in routeWebSocket since\n\t// WebSockets also need to be routed from ManagerDriver.proxyWebSocket and\n\t// ManagerDriver.openWebSocket.\n\trouter.on(\n\t\t\"GET\",\n\t\t[PATH_CONNECT, `${PATH_WEBSOCKET_PREFIX}*`, PATH_INSPECTOR_CONNECT],\n\t\tasync (c) => {\n\t\t\tconst upgradeWebSocket = runConfig.getUpgradeWebSocket?.();\n\t\t\tif (upgradeWebSocket) {\n\t\t\t\treturn upgradeWebSocket(async (c) => {\n\t\t\t\t\tconst protocols = c.req.header(\"sec-websocket-protocol\");\n\t\t\t\t\tconst { encoding, connParams } =\n\t\t\t\t\t\tparseWebSocketProtocols(protocols);\n\n\t\t\t\t\treturn await routeWebSocket(\n\t\t\t\t\t\tc.req.raw,\n\t\t\t\t\t\tc.req.path,\n\t\t\t\t\t\tc.req.header(),\n\t\t\t\t\t\trunConfig,\n\t\t\t\t\t\tactorDriver,\n\t\t\t\t\t\tc.env.actorId,\n\t\t\t\t\t\tencoding,\n\t\t\t\t\t\tconnParams,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\t\t\t\t})(c, noopNext());\n\t\t\t} else {\n\t\t\t\treturn c.text(\n\t\t\t\t\t\"WebSockets are not enabled for this driver.\",\n\t\t\t\t\t400,\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t);\n\n\trouter.post(\"/action/:action\", async (c) => {\n\t\tconst actionName = c.req.param(\"action\");\n\n\t\treturn handleAction(\n\t\t\tc,\n\t\t\trunConfig,\n\t\t\tactorDriver,\n\t\t\tactionName,\n\t\t\tc.env.actorId,\n\t\t);\n\t});\n\n\trouter.all(\"/request/*\", async (c) => {\n\t\t// TODO: This is not a clean way of doing this since `/http/` might exist mid-path\n\t\t// Strip the /http prefix from the URL to get the original path\n\t\tconst url = new URL(c.req.url);\n\t\tconst originalPath = url.pathname.replace(/^\\/request/, \"\") || \"/\";\n\n\t\t// Create a new request with the corrected URL\n\t\tconst correctedUrl = new URL(originalPath + url.search, url.origin);\n\t\tconst correctedRequest = new Request(correctedUrl, {\n\t\t\tmethod: c.req.method,\n\t\t\theaders: c.req.raw.headers,\n\t\t\tbody: c.req.raw.body,\n\t\t\tduplex: \"half\",\n\t\t} as RequestInit);\n\n\t\tloggerWithoutContext().debug({\n\t\t\tmsg: \"rewriting http url\",\n\t\t\tfrom: c.req.url,\n\t\t\tto: correctedRequest.url,\n\t\t});\n\n\t\treturn await handleRawRequest(\n\t\t\tc,\n\t\t\tcorrectedRequest,\n\t\t\tactorDriver,\n\t\t\tc.env.actorId,\n\t\t);\n\t});\n\n\tif (isInspectorEnabled(runConfig, \"actor\")) {\n\t\trouter.route(\n\t\t\t\"/inspect\",\n\t\t\tnew Hono<\n\t\t\t\tActorInspectorRouterEnv & { Bindings: ActorRouterBindings }\n\t\t\t>()\n\t\t\t\t.use(secureInspector(runConfig), async (c, next) => {\n\t\t\t\t\tconst inspector = (\n\t\t\t\t\t\tawait actorDriver.loadActor(c.env.actorId)\n\t\t\t\t\t).inspector;\n\t\t\t\t\tinvariant(\n\t\t\t\t\t\tinspector,\n\t\t\t\t\t\t\"inspector not supported on this platform\",\n\t\t\t\t\t);\n\n\t\t\t\t\tc.set(\"inspector\", inspector);\n\t\t\t\t\treturn next();\n\t\t\t\t})\n\t\t\t\t.route(\"/\", createActorInspectorRouter()),\n\t\t);\n\t}\n\n\trouter.notFound(handleRouteNotFound);\n\trouter.onError(handleRouteError);\n\n\treturn router;\n}\n","import * as cbor from \"cbor-x\";\nimport type { Context as HonoContext, HonoRequest } from \"hono\";\nimport type { AnyConn } from \"@/actor/conn/mod\";\nimport { ActionContext } from \"@/actor/contexts/action\";\nimport * as errors from \"@/actor/errors\";\nimport type { AnyActorInstance } from \"@/actor/instance/mod\";\nimport { type Encoding, EncodingSchema } from \"@/actor/protocol/serde\";\nimport {\n\tHEADER_ACTOR_QUERY,\n\tHEADER_CONN_PARAMS,\n\tHEADER_ENCODING,\n\tWS_PROTOCOL_CONN_PARAMS,\n\tWS_PROTOCOL_ENCODING,\n} from \"@/common/actor-router-consts\";\nimport { stringifyError } from \"@/common/utils\";\nimport type { RunnerConfig } from \"@/registry/run-config\";\nimport type * as protocol from \"@/schemas/client-protocol/mod\";\nimport {\n\tCURRENT_VERSION as CLIENT_PROTOCOL_CURRENT_VERSION,\n\tHTTP_ACTION_REQUEST_VERSIONED,\n\tHTTP_ACTION_RESPONSE_VERSIONED,\n} from \"@/schemas/client-protocol/versioned\";\nimport {\n\ttype HttpActionRequest as HttpActionRequestJson,\n\tHttpActionRequestSchema,\n\ttype HttpActionResponse as HttpActionResponseJson,\n\tHttpActionResponseSchema,\n} from \"@/schemas/client-protocol-zod/mod\";\nimport {\n\tcontentTypeForEncoding,\n\tdeserializeWithEncoding,\n\tserializeWithEncoding,\n} from \"@/serde\";\nimport { bufferToArrayBuffer } from \"@/utils\";\nimport { createHttpDriver } from \"./conn/drivers/http\";\nimport { createRawRequestDriver } from \"./conn/drivers/raw-request\";\nimport type { ActorDriver } from \"./driver\";\nimport { loggerWithoutContext } from \"./log\";\n\nexport interface ActionOpts {\n\treq?: HonoRequest;\n\tparams: unknown;\n\tactionName: string;\n\tactionArgs: unknown[];\n\tactorId: string;\n}\n\nexport interface ActionOutput {\n\toutput: unknown;\n}\n\nexport interface ConnsMessageOpts {\n\treq?: HonoRequest;\n\tconnId: string;\n\tmessage: protocol.ToServer;\n\tactorId: string;\n}\n\nexport interface FetchOpts {\n\trequest: Request;\n\tactorId: string;\n}\n\n/**\n * Creates an action handler\n */\nexport async function handleAction(\n\tc: HonoContext,\n\t_runConfig: RunnerConfig,\n\tactorDriver: ActorDriver,\n\tactionName: string,\n\tactorId: string,\n) {\n\tconst encoding = getRequestEncoding(c.req);\n\tconst parameters = getRequestConnParams(c.req);\n\n\t// Validate incoming request\n\tconst arrayBuffer = await c.req.arrayBuffer();\n\tconst request = deserializeWithEncoding(\n\t\tencoding,\n\t\tnew Uint8Array(arrayBuffer),\n\t\tHTTP_ACTION_REQUEST_VERSIONED,\n\t\tHttpActionRequestSchema,\n\t\t// JSON: args is already the decoded value (raw object/array)\n\t\t(json: HttpActionRequestJson) => json.args,\n\t\t// BARE/CBOR: args is ArrayBuffer that needs CBOR-decoding\n\t\t(bare: protocol.HttpActionRequest) =>\n\t\t\tcbor.decode(new Uint8Array(bare.args)),\n\t);\n\tconst actionArgs = request;\n\n\t// Invoke the action\n\tlet actor: AnyActorInstance | undefined;\n\tlet conn: AnyConn | undefined;\n\tlet output: unknown | undefined;\n\ttry {\n\t\tactor = await actorDriver.loadActor(actorId);\n\n\t\tactor.rLog.debug({ msg: \"handling action\", actionName, encoding });\n\n\t\t// Create conn\n\t\tconn = await actor.connectionManager.prepareAndConnectConn(\n\t\t\tcreateHttpDriver(),\n\t\t\tparameters,\n\t\t\tc.req.raw,\n\t\t\tc.req.path,\n\t\t\tc.req.header(),\n\t\t);\n\n\t\t// Call action\n\t\tconst ctx = new ActionContext(actor, conn!);\n\t\toutput = await actor.executeAction(ctx, actionName, actionArgs);\n\t} finally {\n\t\tif (conn) {\n\t\t\tconn.disconnect();\n\t\t}\n\t}\n\n\t// Send response\n\tconst serialized = serializeWithEncoding(\n\t\tencoding,\n\t\toutput,\n\t\tHTTP_ACTION_RESPONSE_VERSIONED,\n\t\tCLIENT_PROTOCOL_CURRENT_VERSION,\n\t\tHttpActionResponseSchema,\n\t\t// JSON: output is the raw value (will be serialized by jsonStringifyCompat)\n\t\t(value): HttpActionResponseJson => ({ output: value }),\n\t\t// BARE/CBOR: output needs to be CBOR-encoded to ArrayBuffer\n\t\t(value): protocol.HttpActionResponse => ({\n\t\t\toutput: bufferToArrayBuffer(cbor.encode(value)),\n\t\t}),\n\t);\n\n\t// TODO: Remove any, Hono is being a dumbass\n\treturn c.body(serialized as Uint8Array as any, 200, {\n\t\t\"Content-Type\": contentTypeForEncoding(encoding),\n\t});\n}\n\nexport async function handleRawRequest(\n\tc: HonoContext,\n\treq: Request,\n\tactorDriver: ActorDriver,\n\tactorId: string,\n): Promise<Response> {\n\tconst actor = await actorDriver.loadActor(actorId);\n\tconst parameters = getRequestConnParams(c.req);\n\n\t// Track connection outside of scope for cleanup\n\tlet createdConn: AnyConn | undefined;\n\n\ttry {\n\t\tconst conn = await actor.connectionManager.prepareAndConnectConn(\n\t\t\tcreateRawRequestDriver(),\n\t\t\tparameters,\n\t\t\treq,\n\t\t\tc.req.path,\n\t\t\tc.req.header(),\n\t\t);\n\n\t\tcreatedConn = conn;\n\n\t\treturn await actor.handleRawRequest(conn, req);\n\t} finally {\n\t\t// Clean up the connection after the request completes\n\t\tif (createdConn) {\n\t\t\tcreatedConn.disconnect();\n\t\t}\n\t}\n}\n\n// Helper to get the connection encoding from a request\n//\n// Defaults to JSON if not provided so we can support vanilla curl requests easily.\nexport function getRequestEncoding(req: HonoRequest): Encoding {\n\tconst encodingParam = req.header(HEADER_ENCODING);\n\tif (!encodingParam) {\n\t\treturn \"json\";\n\t}\n\n\tconst result = EncodingSchema.safeParse(encodingParam);\n\tif (!result.success) {\n\t\tthrow new errors.InvalidEncoding(encodingParam as string);\n\t}\n\n\treturn result.data;\n}\n\nexport function getRequestExposeInternalError(_req: Request): boolean {\n\t// Unipmlemented\n\treturn false;\n}\n\nexport function getRequestQuery(c: HonoContext): unknown {\n\t// Get query parameters for actor lookup\n\tconst queryParam = c.req.header(HEADER_ACTOR_QUERY);\n\tif (!queryParam) {\n\t\tloggerWithoutContext().error({ msg: \"missing query parameter\" });\n\t\tthrow new errors.InvalidRequest(\"missing query\");\n\t}\n\n\t// Parse the query JSON and validate with schema\n\ttry {\n\t\tconst parsed = JSON.parse(queryParam);\n\t\treturn parsed;\n\t} catch (error) {\n\t\tloggerWithoutContext().error({ msg: \"invalid query json\", error });\n\t\tthrow new errors.InvalidQueryJSON(error);\n\t}\n}\n\n// Helper to get connection parameters for the request\nexport function getRequestConnParams(req: HonoRequest): unknown {\n\tconst paramsParam = req.header(HEADER_CONN_PARAMS);\n\tif (!paramsParam) {\n\t\treturn null;\n\t}\n\n\ttry {\n\t\treturn JSON.parse(paramsParam);\n\t} catch (err) {\n\t\tthrow new errors.InvalidParams(\n\t\t\t`Invalid params JSON: ${stringifyError(err)}`,\n\t\t);\n\t}\n}\n","import type { ConnDriver } from \"../driver\";\nimport { DriverReadyState } from \"../driver\";\n\n/**\n * Creates a raw HTTP connection driver.\n *\n * This driver is used for raw HTTP connections that don't use the RivetKit protocol.\n * Unlike the standard HTTP driver, this provides connection lifecycle management\n * for tracking the HTTP request through the actor's onRequest handler.\n */\nexport function createRawRequestDriver(): ConnDriver {\n\treturn {\n\t\ttype: \"raw-request\",\n\n\t\tdisconnect: async () => {\n\t\t\t// Noop\n\t\t},\n\n\t\tgetConnectionReadyState: (): DriverReadyState | undefined => {\n\t\t\t// HTTP connections are always considered open until the request completes\n\t\t\treturn DriverReadyState.OPEN;\n\t\t},\n\t};\n}\n","import * as cbor from \"cbor-x\";\nimport type { Context as HonoContext, Next } from \"hono\";\nimport type { Encoding } from \"@/actor/protocol/serde\";\nimport {\n\tgetRequestEncoding,\n\tgetRequestExposeInternalError,\n} from \"@/actor/router-endpoints\";\nimport { buildActorNames, type RegistryConfig } from \"@/registry/config\";\nimport type { RunnerConfig } from \"@/registry/run-config\";\nimport type * as protocol from \"@/schemas/client-protocol/mod\";\nimport {\n\tCURRENT_VERSION as CLIENT_PROTOCOL_CURRENT_VERSION,\n\tHTTP_RESPONSE_ERROR_VERSIONED,\n} from \"@/schemas/client-protocol/versioned\";\nimport {\n\ttype HttpResponseError as HttpResponseErrorJson,\n\tHttpResponseErrorSchema,\n} from \"@/schemas/client-protocol-zod/mod\";\nimport { encodingIsBinary, serializeWithEncoding } from \"@/serde\";\nimport { bufferToArrayBuffer, getEnvUniversal, VERSION } from \"@/utils\";\nimport { getLogger, type Logger } from \"./log\";\nimport { deconstructError, stringifyError } from \"./utils\";\n\nexport function logger() {\n\treturn getLogger(\"router\");\n}\n\nexport function loggerMiddleware(logger: Logger) {\n\treturn async (c: HonoContext, next: Next) => {\n\t\tconst method = c.req.method;\n\t\tconst path = c.req.path;\n\t\tconst startTime = Date.now();\n\n\t\tawait next();\n\n\t\tconst duration = Date.now() - startTime;\n\t\tlogger.debug({\n\t\t\tmsg: \"http request\",\n\t\t\tmethod,\n\t\t\tpath,\n\t\t\tstatus: c.res.status,\n\t\t\tdt: `${duration}ms`,\n\t\t\treqSize: c.req.header(\"content-length\"),\n\t\t\tresSize: c.res.headers.get(\"content-length\"),\n\t\t\tuserAgent: c.req.header(\"user-agent\"),\n\t\t\t...(getEnvUniversal(\"_RIVET_LOG_HEADERS\")\n\t\t\t\t? { allHeaders: JSON.stringify(c.req.header()) }\n\t\t\t\t: {}),\n\t\t});\n\t};\n}\n\nexport function handleRouteNotFound(c: HonoContext) {\n\treturn c.text(\"Not Found (RivetKit)\", 404);\n}\n\nexport function handleRouteError(error: unknown, c: HonoContext) {\n\tconst exposeInternalError = getRequestExposeInternalError(c.req.raw);\n\n\tconst { statusCode, group, code, message, metadata } = deconstructError(\n\t\terror,\n\t\tlogger(),\n\t\t{\n\t\t\tmethod: c.req.method,\n\t\t\tpath: c.req.path,\n\t\t},\n\t\texposeInternalError,\n\t);\n\n\tlet encoding: Encoding;\n\ttry {\n\t\tencoding = getRequestEncoding(c.req);\n\t} catch (_) {\n\t\tencoding = \"json\";\n\t}\n\n\tconst errorData = { group, code, message, metadata };\n\tconst output = serializeWithEncoding(\n\t\tencoding,\n\t\terrorData,\n\t\tHTTP_RESPONSE_ERROR_VERSIONED,\n\t\tCLIENT_PROTOCOL_CURRENT_VERSION,\n\t\tHttpResponseErrorSchema,\n\t\t// JSON: metadata is the raw value (will be serialized by jsonStringifyCompat)\n\t\t(value): HttpResponseErrorJson => ({\n\t\t\tgroup: value.group,\n\t\t\tcode: value.code,\n\t\t\tmessage: value.message,\n\t\t\tmetadata: value.metadata,\n\t\t}),\n\t\t// BARE/CBOR: metadata needs to be CBOR-encoded to ArrayBuffer\n\t\t(value): protocol.HttpResponseError => ({\n\t\t\tgroup: value.group,\n\t\t\tcode: value.code,\n\t\t\tmessage: value.message,\n\t\t\tmetadata: value.metadata\n\t\t\t\t? bufferToArrayBuffer(cbor.encode(value.metadata))\n\t\t\t\t: null,\n\t\t}),\n\t);\n\n\t// TODO: Remove any\n\treturn c.body(output as any, { status: statusCode });\n}\n\n/**\n * Metadata response interface for the /metadata endpoint\n */\nexport interface MetadataResponse {\n\truntime: string;\n\tversion: string;\n\trunner?: {\n\t\tkind:\n\t\t\t| { serverless: Record<never, never> }\n\t\t\t| { normal: Record<never, never> };\n\t};\n\tactorNames: ReturnType<typeof buildActorNames>;\n\t/**\n\t * Endpoint that the client should connect to to access this runner.\n\t *\n\t * If defined, will override the endpoint the user has configured on startup.\n\t *\n\t * This is helpful if attempting to connect to a serverless runner, so the serverless runner can define where the main endpoint lives.\n\t *\n\t * This is also helpful for setting up clean redirects as needed.\n\t **/\n\tclientEndpoint?: string;\n}\n\nexport function handleMetadataRequest(\n\tc: HonoContext,\n\tregistryConfig: RegistryConfig,\n\trunConfig: RunnerConfig,\n) {\n\tconst response: MetadataResponse = {\n\t\truntime: \"rivetkit\",\n\t\tversion: VERSION,\n\t\trunner: {\n\t\t\tkind:\n\t\t\t\trunConfig.runnerKind === \"serverless\"\n\t\t\t\t\t? { serverless: {} }\n\t\t\t\t\t: { normal: {} },\n\t\t},\n\t\tactorNames: buildActorNames(registryConfig),\n\t\t// If server address is changed, return a different client endpoint.\n\t\t// Otherwise, return null indicating the client should use the current\n\t\t// endpoint it's already configured with.\n\t\tclientEndpoint: runConfig.overrideServerAddress,\n\t};\n\n\treturn c.json(response);\n}\n\nexport function handleHealthRequest(c: HonoContext) {\n\treturn c.json({\n\t\tstatus: \"ok\",\n\t\truntime: \"rivetkit\",\n\t\tversion: VERSION,\n\t});\n}\n","//! These configs configs hold anything that's not platform-specific about running actors.\n\nimport { z } from \"zod\";\nimport type { ActorDefinition, AnyActorDefinition } from \"@/actor/definition\";\n\nexport const ActorsSchema = z.record(\n\tz.string(),\n\tz.custom<ActorDefinition<any, any, any, any, any, any, any>>(),\n);\nexport type RegistryActors = z.infer<typeof ActorsSchema>;\n\nexport const TestConfigSchema = z.object({ enabled: z.boolean() });\nexport type TestConfig = z.infer<typeof TestConfigSchema>;\n\n/** Base config used for the actor config across all platforms. */\nexport const RegistryConfigSchema = z.object({\n\tuse: z.record(z.string(), z.custom<AnyActorDefinition>()),\n\n\t// TODO: Find a better way of passing around the test config\n\t/**\n\t * Test configuration.\n\t *\n\t * DO NOT MANUALLY ENABLE. THIS IS USED INTERNALLY.\n\t * @internal\n\t **/\n\ttest: TestConfigSchema.optional().default({ enabled: false }),\n});\nexport type RegistryConfig = z.infer<typeof RegistryConfigSchema>;\nexport type RegistryConfigInput<A extends RegistryActors> = Omit<\n\tz.input<typeof RegistryConfigSchema>,\n\t\"use\"\n> & { use: A };\n\nexport function buildActorNames(\n\tregistryConfig: RegistryConfig,\n): Record<string, { metadata: Record<string, any> }> {\n\treturn Object.fromEntries(\n\t\tObject.keys(registryConfig.use).map((name) => [name, { metadata: {} }]),\n\t);\n}\n","import type { WSContext } from \"hono/ws\";\nimport invariant from \"invariant\";\nimport type { AnyConn } from \"@/actor/conn/mod\";\nimport type { AnyActorInstance } from \"@/actor/instance/mod\";\nimport type { InputData } from \"@/actor/protocol/serde\";\nimport { type Encoding, EncodingSchema } from \"@/actor/protocol/serde\";\nimport {\n\tPATH_CONNECT,\n\tPATH_INSPECTOR_CONNECT,\n\tPATH_WEBSOCKET_BASE,\n\tPATH_WEBSOCKET_PREFIX,\n\tWS_PROTOCOL_CONN_PARAMS,\n\tWS_PROTOCOL_ENCODING,\n} from \"@/common/actor-router-consts\";\nimport { deconstructError } from \"@/common/utils\";\nimport type {\n\tRivetMessageEvent,\n\tUniversalWebSocket,\n} from \"@/common/websocket-interface\";\nimport type { RunnerConfig } from \"@/registry/run-config\";\nimport { promiseWithResolvers } from \"@/utils\";\nimport type { ConnDriver } from \"./conn/driver\";\nimport { createRawWebSocketDriver } from \"./conn/drivers/raw-websocket\";\nimport { createWebSocketDriver } from \"./conn/drivers/websocket\";\nimport type { ActorDriver } from \"./driver\";\nimport { loggerWithoutContext } from \"./log\";\nimport { parseMessage } from \"./protocol/old\";\nimport { getRequestExposeInternalError } from \"./router-endpoints\";\n\n// TODO: Merge with ConnectWebSocketOutput interface\nexport interface UpgradeWebSocketArgs {\n\tconn?: AnyConn;\n\tactor?: AnyActorInstance;\n\tonRestore?: (ws: WSContext) => void;\n\tonOpen: (event: any, ws: WSContext) => void;\n\tonMessage: (event: any, ws: WSContext) => void;\n\tonClose: (event: any, ws: WSContext) => void;\n\tonError: (error: any, ws: WSContext) => void;\n}\n\ninterface WebSocketHandlerOpts {\n\trunConfig: RunnerConfig;\n\trequest: Request | undefined;\n\tencoding: Encoding;\n\tactor: AnyActorInstance;\n\tclosePromiseResolvers: ReturnType<typeof promiseWithResolvers<void>>;\n\tconn: AnyConn;\n\texposeInternalError: boolean;\n}\n\n/** Handler for a specific WebSocket route. Used in routeWebSocket. */\ntype WebSocketHandler = (\n\topts: WebSocketHandlerOpts,\n) => Promise<UpgradeWebSocketArgs>;\n\nexport async function routeWebSocket(\n\trequest: Request | undefined,\n\trequestPath: string,\n\trequestHeaders: Record<string, string>,\n\trunConfig: RunnerConfig,\n\tactorDriver: ActorDriver,\n\tactorId: string,\n\tencoding: Encoding,\n\tparameters: unknown,\n\tgatewayId: ArrayBuffer | undefined,\n\trequestId: ArrayBuffer | undefined,\n\tisHibernatable: boolean,\n\tisRestoringHibernatable: boolean,\n): Promise<UpgradeWebSocketArgs> {\n\tconst exposeInternalError = request\n\t\t? getRequestExposeInternalError(request)\n\t\t: false;\n\n\tlet createdConn: AnyConn | undefined;\n\ttry {\n\t\tconst actor = await actorDriver.loadActor(actorId);\n\n\t\tactor.rLog.debug({\n\t\t\tmsg: \"new websocket connection\",\n\t\t\tactorId,\n\t\t\trequestPath,\n\t\t\tisHibernatable,\n\t\t});\n\n\t\t// Promise used to wait for the websocket close in `disconnect`\n\t\tconst closePromiseResolvers = promiseWithResolvers<void>();\n\n\t\t// Route WebSocket & create driver\n\t\tlet handler: WebSocketHandler;\n\t\tlet connDriver: ConnDriver;\n\t\tif (requestPath === PATH_CONNECT) {\n\t\t\tconst { driver, setWebSocket } = createWebSocketDriver(\n\t\t\t\tisHibernatable\n\t\t\t\t\t? { gatewayId: gatewayId!, requestId: requestId! }\n\t\t\t\t\t: undefined,\n\t\t\t\tencoding,\n\t\t\t\tclosePromiseResolvers.promise,\n\t\t\t);\n\t\t\thandler = handleWebSocketConnect.bind(undefined, setWebSocket);\n\t\t\tconnDriver = driver;\n\t\t} else if (\n\t\t\trequestPath === PATH_WEBSOCKET_BASE ||\n\t\t\trequestPath.startsWith(PATH_WEBSOCKET_PREFIX)\n\t\t) {\n\t\t\tconst { driver, setWebSocket } = createRawWebSocketDriver(\n\t\t\t\tisHibernatable\n\t\t\t\t\t? { gatewayId: gatewayId!, requestId: requestId! }\n\t\t\t\t\t: undefined,\n\t\t\t\tclosePromiseResolvers.promise,\n\t\t\t);\n\t\t\thandler = handleRawWebSocket.bind(undefined, setWebSocket);\n\t\t\tconnDriver = driver;\n\t\t} else if (requestPath === PATH_INSPECTOR_CONNECT) {\n\t\t\t// This returns raw UpgradeWebSocketArgs instead of accepting a\n\t\t\t// Conn since this does not need a Conn\n\t\t\treturn await handleWebSocketInspectorConnect();\n\t\t} else {\n\t\t\tthrow `WebSocket Path Not Found: ${requestPath}`;\n\t\t}\n\n\t\t// Prepare connection\n\t\tconst conn = await actor.connectionManager.prepareConn(\n\t\t\tconnDriver,\n\t\t\tparameters,\n\t\t\trequest,\n\t\t\trequestPath,\n\t\t\trequestHeaders,\n\t\t\tisHibernatable,\n\t\t\tisRestoringHibernatable,\n\t\t);\n\t\tcreatedConn = conn;\n\n\t\t// Create handler\n\t\t//\n\t\t// This must call actor.connectionManager.connectConn in onOpen.\n\t\treturn await handler({\n\t\t\trunConfig,\n\t\t\trequest,\n\t\t\tencoding,\n\t\t\tactor,\n\t\t\tclosePromiseResolvers,\n\t\t\tconn,\n\t\t\texposeInternalError,\n\t\t});\n\t} catch (error) {\n\t\tconst { group, code } = deconstructError(\n\t\t\terror,\n\t\t\tloggerWithoutContext(),\n\t\t\t{},\n\t\t\texposeInternalError,\n\t\t);\n\n\t\t// Clean up connection\n\t\tif (createdConn) {\n\t\t\tcreatedConn.disconnect(`${group}.${code}`);\n\t\t}\n\n\t\t// Return handler that immediately closes with error\n\t\t// Note: createdConn should always exist here, but we use a type assertion for safety\n\t\treturn {\n\t\t\tconn: createdConn!,\n\t\t\tonOpen: (_evt: any, ws: WSContext) => {\n\t\t\t\tws.close(1011, code);\n\t\t\t},\n\t\t\tonMessage: (_evt: { data: any }, ws: WSContext) => {\n\t\t\t\tws.close(1011, \"actor.not_loaded\");\n\t\t\t},\n\t\t\tonClose: (_event: any, _ws: WSContext) => {},\n\t\t\tonError: (_error: unknown) => {},\n\t\t};\n\t}\n}\n\n/**\n * Creates a WebSocket connection handler\n */\nexport async function handleWebSocketConnect(\n\tsetWebSocket: (ws: WSContext) => void,\n\t{\n\t\trunConfig,\n\t\tencoding,\n\t\tactor,\n\t\tclosePromiseResolvers,\n\t\tconn,\n\t\texposeInternalError,\n\t}: WebSocketHandlerOpts,\n): Promise<UpgradeWebSocketArgs> {\n\treturn {\n\t\tconn,\n\t\tactor,\n\t\tonRestore: (ws: WSContext) => {\n\t\t\tsetWebSocket(ws);\n\t\t},\n\t\t// NOTE: onOpen cannot be async since this messes up the open event listener order\n\t\tonOpen: (_evt: any, ws: WSContext) => {\n\t\t\tactor.rLog.debug(\"actor websocket open\");\n\n\t\t\tsetWebSocket(ws);\n\n\t\t\t// This will not be called by restoring hibernatable\n\t\t\t// connections. All restoration is done in prepareConn.\n\t\t\tactor.connectionManager.connectConn(conn);\n\t\t},\n\t\tonMessage: (evt: RivetMessageEvent, ws: WSContext) => {\n\t\t\t// Handle message asynchronously\n\t\t\tactor.rLog.debug({ msg: \"received message\" });\n\n\t\t\tconst value = evt.data.valueOf() as InputData;\n\t\t\tparseMessage(value, {\n\t\t\t\tencoding: encoding,\n\t\t\t\tmaxIncomingMessageSize: runConfig.maxIncomingMessageSize,\n\t\t\t})\n\t\t\t\t.then((message) => {\n\t\t\t\t\tactor.processMessage(message, conn).catch((error) => {\n\t\t\t\t\t\tconst { code } = deconstructError(\n\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t\tactor.rLog,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\twsEvent: \"message\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\texposeInternalError,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tws.close(1011, code);\n\t\t\t\t\t});\n\t\t\t\t})\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tconst { code } = deconstructError(\n\t\t\t\t\t\terror,\n\t\t\t\t\t\tactor.rLog,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twsEvent: \"message\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\texposeInternalError,\n\t\t\t\t\t);\n\t\t\t\t\tws.close(1011, code);\n\t\t\t\t});\n\t\t},\n\t\tonClose: (\n\t\t\tevent: {\n\t\t\t\twasClean: boolean;\n\t\t\t\tcode: number;\n\t\t\t\treason: string;\n\t\t\t},\n\t\t\tws: WSContext,\n\t\t) => {\n\t\t\tclosePromiseResolvers.resolve();\n\n\t\t\tif (event.wasClean) {\n\t\t\t\tactor.rLog.info({\n\t\t\t\t\tmsg: \"websocket closed\",\n\t\t\t\t\tcode: event.code,\n\t\t\t\t\treason: event.reason,\n\t\t\t\t\twasClean: event.wasClean,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tactor.rLog.warn({\n\t\t\t\t\tmsg: \"websocket closed\",\n\t\t\t\t\tcode: event.code,\n\t\t\t\t\treason: event.reason,\n\t\t\t\t\twasClean: event.wasClean,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// HACK: Close socket in order to fix bug with Cloudflare leaving WS in closing state\n\t\t\t// https://github.com/cloudflare/workerd/issues/2569\n\t\t\tws.close(1000, \"hack_force_close\");\n\n\t\t\t// Wait for actor.createConn to finish before removing the connection\n\t\t\tconn.disconnect(event?.reason);\n\t\t},\n\t\tonError: (_error: unknown) => {\n\t\t\ttry {\n\t\t\t\t// Actors don't need to know about this, since it's abstracted away\n\t\t\t\tactor.rLog.warn({ msg: \"websocket error\" });\n\t\t\t} catch (error) {\n\t\t\t\tdeconstructError(\n\t\t\t\t\terror,\n\t\t\t\t\tactor.rLog,\n\t\t\t\t\t{ wsEvent: \"error\" },\n\t\t\t\t\texposeInternalError,\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t};\n}\n\nexport async function handleRawWebSocket(\n\tsetWebSocket: (ws: UniversalWebSocket) => void,\n\t{ request, actor, closePromiseResolvers, conn }: WebSocketHandlerOpts,\n): Promise<UpgradeWebSocketArgs> {\n\treturn {\n\t\tconn,\n\t\tactor,\n\t\tonRestore: (wsContext: WSContext) => {\n\t\t\tconst ws = wsContext.raw as UniversalWebSocket;\n\t\t\tinvariant(ws, \"missing wsContext.raw\");\n\n\t\t\tsetWebSocket(ws);\n\t\t},\n\t\t// NOTE: onOpen cannot be async since this will cause the client's open\n\t\t// event to be called before this completes. Do all async work in\n\t\t// handleRawWebSocket root.\n\t\tonOpen: (_evt: any, wsContext: WSContext) => {\n\t\t\tconst ws = wsContext.raw as UniversalWebSocket;\n\t\t\tinvariant(ws, \"missing wsContext.raw\");\n\n\t\t\tsetWebSocket(ws);\n\n\t\t\t// This will not be called by restoring hibernatable\n\t\t\t// connections. All restoration is done in prepareConn.\n\t\t\tactor.connectionManager.connectConn(conn);\n\n\t\t\t// Call the actor's onWebSocket handler with the adapted WebSocket\n\t\t\t//\n\t\t\t// NOTE: onWebSocket is called inside this function. Make sure\n\t\t\t// this is called synchronously within onOpen.\n\t\t\tactor.handleRawWebSocket(conn, ws, request);\n\t\t},\n\t\tonMessage: (event: any, ws: any) => {\n\t\t\t// Find the adapter for this WebSocket\n\t\t\tconst adapter = (ws as any).__adapter;\n\t\t\tif (adapter) {\n\t\t\t\tadapter._handleMessage(event);\n\t\t\t}\n\t\t},\n\t\tonClose: (evt: any, ws: any) => {\n\t\t\t// Resolve the close promise\n\t\t\tclosePromiseResolvers.resolve();\n\n\t\t\t// Clean up the connection\n\t\t\tconn.disconnect(evt?.reason);\n\t\t},\n\t\tonError: (error: any, ws: any) => {},\n\t};\n}\n\nexport async function handleWebSocketInspectorConnect(): Promise<UpgradeWebSocketArgs> {\n\treturn {\n\t\t// NOTE: onOpen cannot be async since this messes up the open event listener order\n\t\tonOpen: (_evt: any, ws: WSContext) => {\n\t\t\tws.send(\"Hello world\");\n\t\t},\n\t\tonMessage: (evt: RivetMessageEvent, ws: WSContext) => {\n\t\t\tws.send(\"Pong\");\n\t\t},\n\t\tonClose: (\n\t\t\tevent: {\n\t\t\t\twasClean: boolean;\n\t\t\t\tcode: number;\n\t\t\t\treason: string;\n\t\t\t},\n\t\t\tws: WSContext,\n\t\t) => {\n\t\t\t// TODO:\n\t\t},\n\t\tonError: (_error: unknown) => {\n\t\t\t// TODO:\n\t\t},\n\t};\n}\n\n/**\n * Parse encoding and connection parameters from WebSocket Sec-WebSocket-Protocol header\n */\nexport function parseWebSocketProtocols(protocols: string | null | undefined): {\n\tencoding: Encoding;\n\tconnParams: unknown;\n} {\n\tlet encodingRaw: string | undefined;\n\tlet connParamsRaw: string | undefined;\n\n\tif (protocols) {\n\t\tconst protocolList = protocols.split(\",\").map((p) => p.trim());\n\t\tfor (const protocol of protocolList) {\n\t\t\tif (protocol.startsWith(WS_PROTOCOL_ENCODING)) {\n\t\t\t\tencodingRaw = protocol.substring(WS_PROTOCOL_ENCODING.length);\n\t\t\t} else if (protocol.startsWith(WS_PROTOCOL_CONN_PARAMS)) {\n\t\t\t\tconnParamsRaw = decodeURIComponent(\n\t\t\t\t\tprotocol.substring(WS_PROTOCOL_CONN_PARAMS.length),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst encoding = EncodingSchema.parse(encodingRaw);\n\tconst connParams = connParamsRaw ? JSON.parse(connParamsRaw) : undefined;\n\n\treturn { encoding, connParams };\n}\n\n/**\n * Truncase the PATH_WEBSOCKET_PREFIX path prefix in order to pass a clean\n * path to the onWebSocket handler.\n *\n * Example:\n * - `/websocket/foo` -> `/foo`\n * - `/websocket` -> `/`\n */\nexport function truncateRawWebSocketPathPrefix(path: string): string {\n\t// Extract the path after prefix and preserve query parameters\n\t// Use URL API for cleaner parsing\n\tconst url = new URL(path, \"http://actor\");\n\tconst pathname = url.pathname.replace(/^\\/websocket\\/?/, \"\") || \"/\";\n\tconst normalizedPath =\n\t\t(pathname.startsWith(\"/\") ? pathname : `/${pathname}`) + url.search;\n\n\treturn normalizedPath;\n}\n","import type { AnyConn } from \"@/actor/conn/mod\";\nimport type { AnyActorInstance } from \"@/actor/instance/mod\";\nimport type { UniversalWebSocket } from \"@/common/websocket-interface\";\nimport { loggerWithoutContext } from \"../../log\";\nimport { type ConnDriver, DriverReadyState } from \"../driver\";\n\n/**\n * Creates a raw WebSocket connection driver.\n *\n * This driver is used for raw WebSocket connections that don't use the RivetKit protocol.\n * Unlike the standard WebSocket driver, this doesn't have sendMessage since raw WebSockets\n * don't handle messages from the RivetKit protocol - they handle messages directly in the\n * actor's onWebSocket handler.\n */\nexport function createRawWebSocketDriver(\n\thibernatable: ConnDriver[\"hibernatable\"],\n\tclosePromise: Promise<void>,\n): { driver: ConnDriver; setWebSocket(ws: UniversalWebSocket): void } {\n\tlet websocket: UniversalWebSocket | undefined;\n\n\tconst driver: ConnDriver = {\n\t\ttype: \"raw-websocket\",\n\t\thibernatable,\n\n\t\t// No sendMessage implementation since this is a raw WebSocket that doesn't\n\t\t// handle messages from the RivetKit protocol\n\n\t\tdisconnect: async (\n\t\t\t_actor: AnyActorInstance,\n\t\t\t_conn: AnyConn,\n\t\t\treason?: string,\n\t\t) => {\n\t\t\tif (!websocket) {\n\t\t\t\tloggerWithoutContext().warn(\n\t\t\t\t\t\"disconnecting raw ws without websocket\",\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Close socket\n\t\t\twebsocket.close(1000, reason);\n\n\t\t\t// Wait for socket to close gracefully\n\t\t\tawait closePromise;\n\t\t},\n\n\t\tterminate: () => {\n\t\t\t(websocket as any)?.terminate?.();\n\t\t},\n\n\t\tgetConnectionReadyState: (\n\t\t\t_actor: AnyActorInstance,\n\t\t\t_conn: AnyConn,\n\t\t): DriverReadyState | undefined => {\n\t\t\treturn websocket?.readyState ?? DriverReadyState.CONNECTING;\n\t\t},\n\t};\n\n\treturn {\n\t\tdriver,\n\t\tsetWebSocket(ws) {\n\t\t\twebsocket = ws;\n\t\t},\n\t};\n}\n","import type { WSContext } from \"hono/ws\";\nimport type { AnyConn } from \"@/actor/conn/mod\";\nimport type { AnyActorInstance } from \"@/actor/instance/mod\";\nimport type { CachedSerializer, Encoding } from \"@/actor/protocol/serde\";\nimport { loggerWithoutContext } from \"../../log\";\nimport { type ConnDriver, DriverReadyState } from \"../driver\";\n\nexport type ConnDriverWebSocketState = Record<never, never>;\n\nexport function createWebSocketDriver(\n\thibernatable: ConnDriver[\"hibernatable\"],\n\tencoding: Encoding,\n\tclosePromise: Promise<void>,\n): { driver: ConnDriver; setWebSocket(ws: WSContext): void } {\n\tloggerWithoutContext().debug({\n\t\tmsg: \"createWebSocketDriver creating driver\",\n\t\thibernatable,\n\t});\n\t// Wait for WS to open\n\tlet websocket: WSContext | undefined;\n\n\tconst driver: ConnDriver = {\n\t\ttype: \"websocket\",\n\t\thibernatable,\n\t\trivetKitProtocol: {\n\t\t\tsendMessage: (\n\t\t\t\tactor: AnyActorInstance,\n\t\t\t\tconn: AnyConn,\n\t\t\t\tmessage: CachedSerializer<any, any, any>,\n\t\t\t) => {\n\t\t\t\tif (!websocket) {\n\t\t\t\t\tactor.rLog.warn({\n\t\t\t\t\t\tmsg: \"websocket not open\",\n\t\t\t\t\t\tconnId: conn.id,\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (websocket.readyState !== DriverReadyState.OPEN) {\n\t\t\t\t\tactor.rLog.warn({\n\t\t\t\t\t\tmsg: \"attempting to send message to closed websocket, this is likely a bug in RivetKit\",\n\t\t\t\t\t\tconnId: conn.id,\n\t\t\t\t\t\twsReadyState: websocket.readyState,\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst serialized = message.serialize(encoding);\n\n\t\t\t\tactor.rLog.debug({\n\t\t\t\t\tmsg: \"sending websocket message\",\n\t\t\t\t\tencoding: encoding,\n\t\t\t\t\tdataType: typeof serialized,\n\t\t\t\t\tisUint8Array: serialized instanceof Uint8Array,\n\t\t\t\t\tisArrayBuffer: serialized instanceof ArrayBuffer,\n\t\t\t\t\tdataLength:\n\t\t\t\t\t\t(serialized as any).byteLength ||\n\t\t\t\t\t\t(serialized as any).length,\n\t\t\t\t});\n\n\t\t\t\t// Convert Uint8Array to ArrayBuffer for proper transmission\n\t\t\t\tif (serialized instanceof Uint8Array) {\n\t\t\t\t\tconst buffer = serialized.buffer.slice(\n\t\t\t\t\t\tserialized.byteOffset,\n\t\t\t\t\t\tserialized.byteOffset + serialized.byteLength,\n\t\t\t\t\t);\n\t\t\t\t\t// Handle SharedArrayBuffer case\n\t\t\t\t\tif (buffer instanceof SharedArrayBuffer) {\n\t\t\t\t\t\tconst arrayBuffer = new ArrayBuffer(buffer.byteLength);\n\t\t\t\t\t\tnew Uint8Array(arrayBuffer).set(new Uint8Array(buffer));\n\t\t\t\t\t\tactor.rLog.debug({\n\t\t\t\t\t\t\tmsg: \"converted SharedArrayBuffer to ArrayBuffer\",\n\t\t\t\t\t\t\tbyteLength: arrayBuffer.byteLength,\n\t\t\t\t\t\t});\n\t\t\t\t\t\twebsocket.send(arrayBuffer);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tactor.rLog.debug({\n\t\t\t\t\t\t\tmsg: \"sending ArrayBuffer\",\n\t\t\t\t\t\t\tbyteLength: buffer.byteLength,\n\t\t\t\t\t\t});\n\t\t\t\t\t\twebsocket.send(buffer);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tactor.rLog.debug({\n\t\t\t\t\t\tmsg: \"sending string data\",\n\t\t\t\t\t\tlength: (serialized as string).length,\n\t\t\t\t\t});\n\t\t\t\t\twebsocket.send(serialized);\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\n\t\tdisconnect: async (\n\t\t\t_actor: AnyActorInstance,\n\t\t\t_conn: AnyConn,\n\t\t\treason?: string,\n\t\t) => {\n\t\t\tif (!websocket) {\n\t\t\t\tloggerWithoutContext().warn(\n\t\t\t\t\t\"disconnecting ws without websocket\",\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Close socket\n\t\t\twebsocket.close(1000, reason);\n\n\t\t\t// Create promise to wait for socket to close gracefully\n\t\t\tawait closePromise;\n\t\t},\n\n\t\tterminate: () => {\n\t\t\t(websocket as any).terminate();\n\t\t},\n\n\t\tgetConnectionReadyState: (\n\t\t\t_actor: AnyActorInstance,\n\t\t\t_conn: AnyConn,\n\t\t): DriverReadyState | undefined => {\n\t\t\treturn websocket?.readyState ?? DriverReadyState.CONNECTING;\n\t\t},\n\t};\n\n\treturn {\n\t\tdriver,\n\t\tsetWebSocket(ws) {\n\t\t\twebsocket = ws;\n\t\t},\n\t};\n}\n","import {\n\ttype Actions,\n\ttype ActorConfig,\n\ttype ActorConfigInput,\n\tActorConfigSchema,\n\tActorTypes,\n} from \"./config\";\nimport type { AnyDatabaseProvider } from \"./database\";\nimport { ActorDefinition } from \"./definition\";\n\nexport function actor<\n\tTState,\n\tTConnParams,\n\tTConnState,\n\tTVars,\n\tTInput,\n\tTDatabase extends AnyDatabaseProvider,\n\tTActions extends Actions<\n\t\tTState,\n\t\tTConnParams,\n\t\tTConnState,\n\t\tTVars,\n\t\tTInput,\n\t\tTDatabase\n\t>,\n>(\n\tinput: ActorConfigInput<\n\t\tTState,\n\t\tTConnParams,\n\t\tTConnState,\n\t\tTVars,\n\t\tTInput,\n\t\tTDatabase,\n\t\tTActions\n\t>,\n): ActorDefinition<\n\tTState,\n\tTConnParams,\n\tTConnState,\n\tTVars,\n\tTInput,\n\tTDatabase,\n\tTActions\n> {\n\tconst config = ActorConfigSchema.parse(input) as ActorConfig<\n\t\tTState,\n\t\tTConnParams,\n\t\tTConnState,\n\t\tTVars,\n\t\tTInput,\n\t\tTDatabase\n\t>;\n\treturn new ActorDefinition(config);\n}\nexport type { Encoding } from \"@/actor/protocol/serde\";\nexport {\n\tALLOWED_PUBLIC_HEADERS,\n\tPATH_CONNECT,\n\tPATH_WEBSOCKET_PREFIX,\n} from \"@/common/actor-router-consts\";\nexport type {\n\tUniversalErrorEvent,\n\tUniversalEvent,\n\tUniversalEventSource,\n\tUniversalMessageEvent,\n} from \"@/common/eventsource-interface\";\nexport type {\n\tRivetCloseEvent,\n\tRivetEvent,\n\tRivetMessageEvent,\n\tUniversalWebSocket,\n} from \"@/common/websocket-interface\";\nexport type { ActorKey } from \"@/manager/protocol/query\";\nexport type * from \"./config\";\nexport type { InitContext } from \"./config\";\nexport type { AnyConn, Conn } from \"./conn/mod\";\nexport type { ActionContext } from \"./contexts/action\";\nexport type { ActorContext } from \"./contexts/actor\";\nexport type { ConnContext } from \"./contexts/conn\";\nexport type { ConnInitContext } from \"./contexts/conn-init\";\nexport type { CreateConnStateContext } from \"./contexts/create-conn-state\";\nexport type { OnBeforeConnectContext } from \"./contexts/on-before-connect\";\nexport type { OnConnectContext } from \"./contexts/on-connect\";\nexport type { RequestContext } from \"./contexts/request\";\nexport type { WebSocketContext } from \"./contexts/websocket\";\nexport type {\n\tActionContextOf,\n\tActorContextOf,\n\tActorDefinition,\n\tAnyActorDefinition,\n} from \"./definition\";\nexport { lookupInRegistry } from \"./definition\";\nexport { UserError, type UserErrorOptions } from \"./errors\";\nexport type { AnyActorInstance } from \"./instance/mod\";\nexport {\n\ttype ActorRouter,\n\tcreateActorRouter,\n} from \"./router\";\nexport { routeWebSocket } from \"./router-websocket-endpoints\";\n","import { WSContext } from \"hono/ws\";\nimport type { UpgradeWebSocketArgs } from \"@/actor/router-websocket-endpoints\";\nimport type {\n\tRivetCloseEvent,\n\tRivetEvent,\n\tRivetMessageEvent,\n\tUniversalWebSocket,\n} from \"@/common/websocket-interface\";\nimport { getLogger } from \"./log\";\n\nexport function logger() {\n\treturn getLogger(\"fake-event-source2\");\n}\n\n/**\n * InlineWebSocketAdapter implements a WebSocket-like interface\n * that connects to a UpgradeWebSocketArgs handler\n */\nexport class InlineWebSocketAdapter implements UniversalWebSocket {\n\t// WebSocket readyState values\n\treadonly CONNECTING = 0 as const;\n\treadonly OPEN = 1 as const;\n\treadonly CLOSING = 2 as const;\n\treadonly CLOSED = 3 as const;\n\n\t// Private properties\n\t#handler: UpgradeWebSocketArgs;\n\t#wsContext: WSContext;\n\t#readyState: 0 | 1 | 2 | 3 = 0; // Start in CONNECTING state\n\t#queuedMessages: Array<string | ArrayBuffer | Uint8Array> = [];\n\n\t// Event listeners\n\t#eventListeners: Map<string, ((ev: any) => void)[]> = new Map();\n\n\tconstructor(handler: UpgradeWebSocketArgs) {\n\t\tthis.#handler = handler;\n\n\t\t// Create a fake WSContext to pass to the handler\n\t\tthis.#wsContext = new WSContext({\n\t\t\traw: this,\n\t\t\tsend: (data: string | ArrayBuffer | Uint8Array) => {\n\t\t\t\tlogger().debug({ msg: \"WSContext.send called\" });\n\t\t\t\tthis.#handleMessage(data);\n\t\t\t},\n\t\t\tclose: (code?: number, reason?: string) => {\n\t\t\t\tlogger().debug({ msg: \"WSContext.close called\", code, reason });\n\t\t\t\tthis.#handleClose(code || 1000, reason || \"\");\n\t\t\t},\n\t\t\t// Set readyState to 1 (OPEN) since handlers expect an open connection\n\t\t\treadyState: 1,\n\t\t});\n\n\t\t// Initialize the connection\n\t\t//\n\t\t// Defer initialization to allow event listeners to be attached first\n\t\tsetTimeout(() => {\n\t\t\tthis.#initialize();\n\t\t}, 0);\n\t}\n\n\tget readyState(): 0 | 1 | 2 | 3 {\n\t\treturn this.#readyState;\n\t}\n\n\tget binaryType(): \"arraybuffer\" | \"blob\" {\n\t\treturn \"arraybuffer\";\n\t}\n\n\tset binaryType(value: \"arraybuffer\" | \"blob\") {\n\t\t// Ignored for now - always use arraybuffer\n\t}\n\n\tget bufferedAmount(): number {\n\t\treturn 0; // Not tracked in InlineWebSocketAdapter\n\t}\n\n\tget extensions(): string {\n\t\treturn \"\"; // Not available in InlineWebSocketAdapter\n\t}\n\n\tget protocol(): string {\n\t\treturn \"\"; // Not available in InlineWebSocketAdapter\n\t}\n\n\tget url(): string {\n\t\treturn \"\"; // Not available in InlineWebSocketAdapter\n\t}\n\n\tsend(data: string | ArrayBufferLike | Blob | ArrayBufferView): void {\n\t\tlogger().debug({ msg: \"send called\", readyState: this.readyState });\n\n\t\t// Handle different ready states\n\t\tif (this.readyState === this.CONNECTING) {\n\t\t\t// Throw InvalidStateError if still connecting\n\t\t\tthrow new DOMException(\n\t\t\t\t\"WebSocket is still in CONNECTING state\",\n\t\t\t\t\"InvalidStateError\",\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\tthis.readyState === this.CLOSING ||\n\t\t\tthis.readyState === this.CLOSED\n\t\t) {\n\t\t\t// Silently ignore if closing or closed\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"ignoring send, websocket is closing or closed\",\n\t\t\t\treadyState: this.readyState,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\t// Must be OPEN at this point\n\t\tthis.#handler.onMessage({ data }, this.#wsContext);\n\t}\n\n\t/**\n\t * Closes the connection\n\t */\n\tclose(code = 1000, reason = \"\"): void {\n\t\tif (\n\t\t\tthis.readyState === this.CLOSED ||\n\t\t\tthis.readyState === this.CLOSING\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tlogger().debug({ msg: \"closing fake websocket\", code, reason });\n\n\t\tthis.#readyState = this.CLOSING;\n\n\t\t// Call the handler's onClose method\n\t\ttry {\n\t\t\tthis.#handler.onClose(\n\t\t\t\t{ code, reason, wasClean: true },\n\t\t\t\tthis.#wsContext,\n\t\t\t);\n\t\t} catch (err) {\n\t\t\tlogger().error({ msg: \"error closing websocket\", error: err });\n\t\t} finally {\n\t\t\tthis.#readyState = this.CLOSED;\n\n\t\t\t// Fire the close event\n\t\t\t// Create a close event object since CloseEvent is not available in Node.js\n\t\t\tconst closeEvent = {\n\t\t\t\ttype: \"close\",\n\t\t\t\twasClean: code === 1000,\n\t\t\t\tcode,\n\t\t\t\treason,\n\t\t\t\ttarget: this,\n\t\t\t\tcurrentTarget: this,\n\t\t\t} as unknown as RivetCloseEvent;\n\n\t\t\tthis.#fireClose(closeEvent);\n\t\t}\n\t}\n\n\t/**\n\t * Initialize the connection with the handler\n\t */\n\tasync #initialize(): Promise<void> {\n\t\ttry {\n\t\t\tlogger().debug({ msg: \"fake websocket initializing\" });\n\n\t\t\t// Call the handler's onOpen method\n\t\t\tlogger().debug({ msg: \"calling handler.onOpen with WSContext\" });\n\t\t\tthis.#handler.onOpen(undefined, this.#wsContext);\n\n\t\t\t// Update the ready state and fire events\n\t\t\tthis.#readyState = this.OPEN;\n\t\t\tlogger().debug({ msg: \"fake websocket initialized and now OPEN\" });\n\n\t\t\t// Fire the open event\n\t\t\tthis.#fireOpen();\n\n\t\t\t// Delay processing queued messages slightly to allow event handlers to be set up\n\t\t\tif (this.#queuedMessages.length > 0) {\n\t\t\t\tif (this.readyState !== this.OPEN) {\n\t\t\t\t\tlogger().warn({\n\t\t\t\t\t\tmsg: \"socket no longer open, dropping queued messages\",\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlogger().debug({\n\t\t\t\t\tmsg: `now processing ${this.#queuedMessages.length} queued messages`,\n\t\t\t\t});\n\n\t\t\t\t// Create a copy to avoid issues if new messages arrive during processing\n\t\t\t\tconst messagesToProcess = [...this.#queuedMessages];\n\t\t\t\tthis.#queuedMessages = [];\n\n\t\t\t\t// Process each queued message\n\t\t\t\tfor (const message of messagesToProcess) {\n\t\t\t\t\tlogger().debug({ msg: \"processing queued message\" });\n\t\t\t\t\tthis.#handleMessage(message);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tlogger().error({\n\t\t\t\tmsg: \"error opening fake websocket\",\n\t\t\t\terror: err,\n\t\t\t\terrorMessage: err instanceof Error ? err.message : String(err),\n\t\t\t\tstack: err instanceof Error ? err.stack : undefined,\n\t\t\t});\n\t\t\tthis.#fireError(err);\n\t\t\tthis.close(1011, \"Internal error during initialization\");\n\t\t}\n\t}\n\n\t/**\n\t * Handle messages received from the server via the WSContext\n\t */\n\t#handleMessage(data: string | ArrayBuffer | Uint8Array): void {\n\t\t// Store messages that arrive before the socket is fully initialized\n\t\tif (this.readyState !== this.OPEN) {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"message received before socket is OPEN, queuing\",\n\t\t\t\treadyState: this.readyState,\n\t\t\t\tdataType: typeof data,\n\t\t\t\tdataLength:\n\t\t\t\t\ttypeof data === \"string\"\n\t\t\t\t\t\t? data.length\n\t\t\t\t\t\t: data instanceof ArrayBuffer\n\t\t\t\t\t\t\t? data.byteLength\n\t\t\t\t\t\t\t: data instanceof Uint8Array\n\t\t\t\t\t\t\t\t? data.byteLength\n\t\t\t\t\t\t\t\t: \"unknown\",\n\t\t\t});\n\n\t\t\t// Queue the message to be processed once the socket is open\n\t\t\tthis.#queuedMessages.push(data);\n\t\t\treturn;\n\t\t}\n\n\t\t// Log message received from server\n\t\tlogger().debug({\n\t\t\tmsg: \"fake websocket received message from server\",\n\t\t\tdataType: typeof data,\n\t\t\tdataLength:\n\t\t\t\ttypeof data === \"string\"\n\t\t\t\t\t? data.length\n\t\t\t\t\t: data instanceof ArrayBuffer\n\t\t\t\t\t\t? data.byteLength\n\t\t\t\t\t\t: data instanceof Uint8Array\n\t\t\t\t\t\t\t? data.byteLength\n\t\t\t\t\t\t\t: \"unknown\",\n\t\t});\n\n\t\t// Create a MessageEvent-like object\n\t\tconst event = {\n\t\t\ttype: \"message\",\n\t\t\tdata,\n\t\t\ttarget: this,\n\t\t\tcurrentTarget: this,\n\t\t} as unknown as RivetMessageEvent;\n\n\t\t// Dispatch the event\n\t\tthis.#dispatchEvent(\"message\", event);\n\t}\n\n\t#handleClose(code: number, reason: string): void {\n\t\tif (this.readyState === this.CLOSED) return;\n\n\t\tthis.#readyState = this.CLOSED;\n\n\t\t// Create a CloseEvent-like object\n\t\tconst event = {\n\t\t\ttype: \"close\",\n\t\t\tcode,\n\t\t\treason,\n\t\t\twasClean: code === 1000,\n\t\t\ttarget: this,\n\t\t\tcurrentTarget: this,\n\t\t} as unknown as RivetCloseEvent;\n\n\t\t// Dispatch the event\n\t\tthis.#dispatchEvent(\"close\", event);\n\t}\n\n\taddEventListener(type: string, listener: (ev: any) => void): void {\n\t\tif (!this.#eventListeners.has(type)) {\n\t\t\tthis.#eventListeners.set(type, []);\n\t\t}\n\t\tthis.#eventListeners.get(type)!.push(listener);\n\t}\n\n\tremoveEventListener(type: string, listener: (ev: any) => void): void {\n\t\tconst listeners = this.#eventListeners.get(type);\n\t\tif (listeners) {\n\t\t\tconst index = listeners.indexOf(listener);\n\t\t\tif (index !== -1) {\n\t\t\t\tlisteners.splice(index, 1);\n\t\t\t}\n\t\t}\n\t}\n\n\t#dispatchEvent(type: string, event: any): void {\n\t\tconst listeners = this.#eventListeners.get(type);\n\t\tif (listeners && listeners.length > 0) {\n\t\t\tlogger().debug(\n\t\t\t\t`dispatching ${type} event to ${listeners.length} listeners`,\n\t\t\t);\n\t\t\tfor (const listener of listeners) {\n\t\t\t\ttry {\n\t\t\t\t\tlistener(event);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tlogger().error({\n\t\t\t\t\t\tmsg: `error in ${type} event listener`,\n\t\t\t\t\t\terror: err,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Also check for on* properties\n\t\tswitch (type) {\n\t\t\tcase \"open\":\n\t\t\t\tif (this.#onopen) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.#onopen(event);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tlogger().error({\n\t\t\t\t\t\t\tmsg: \"error in onopen handler\",\n\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"close\":\n\t\t\t\tif (this.#onclose) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.#onclose(event);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tlogger().error({\n\t\t\t\t\t\t\tmsg: \"error in onclose handler\",\n\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"error\":\n\t\t\t\tif (this.#onerror) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.#onerror(event);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tlogger().error({\n\t\t\t\t\t\t\tmsg: \"error in onerror handler\",\n\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"message\":\n\t\t\t\tif (this.#onmessage) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.#onmessage(event);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tlogger().error({\n\t\t\t\t\t\t\tmsg: \"error in onmessage handler\",\n\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tdispatchEvent(event: RivetEvent): boolean {\n\t\tthis.#dispatchEvent(event.type, event);\n\t\treturn true;\n\t}\n\n\t#fireOpen(): void {\n\t\ttry {\n\t\t\t// Create an Event-like object since Event constructor may not be available\n\t\t\tconst event = {\n\t\t\t\ttype: \"open\",\n\t\t\t\ttarget: this,\n\t\t\t\tcurrentTarget: this,\n\t\t\t} as unknown as RivetEvent;\n\n\t\t\tthis.#dispatchEvent(\"open\", event);\n\t\t} catch (err) {\n\t\t\tlogger().error({ msg: \"error in open event\", error: err });\n\t\t}\n\t}\n\n\t#fireClose(event: RivetCloseEvent): void {\n\t\ttry {\n\t\t\tthis.#dispatchEvent(\"close\", event);\n\t\t} catch (err) {\n\t\t\tlogger().error({ msg: \"error in close event\", error: err });\n\t\t}\n\t}\n\n\t#fireError(error: unknown): void {\n\t\ttry {\n\t\t\t// Create an Event-like object for error\n\t\t\tconst event = {\n\t\t\t\ttype: \"error\",\n\t\t\t\ttarget: this,\n\t\t\t\tcurrentTarget: this,\n\t\t\t\terror,\n\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t} as unknown as RivetEvent;\n\n\t\t\tthis.#dispatchEvent(\"error\", event);\n\t\t} catch (err) {\n\t\t\tlogger().error({ msg: \"error in error event\", error: err });\n\t\t}\n\n\t\t// Log the error\n\t\tlogger().error({ msg: \"websocket error\", error });\n\t}\n\n\t// Event handler properties with getters/setters\n\t#onopen: ((event: RivetEvent) => void) | null = null;\n\t#onclose: ((event: RivetCloseEvent) => void) | null = null;\n\t#onerror: ((event: RivetEvent) => void) | null = null;\n\t#onmessage: ((event: RivetMessageEvent) => void) | null = null;\n\n\tget onopen(): ((event: RivetEvent) => void) | null {\n\t\treturn this.#onopen;\n\t}\n\tset onopen(handler: ((event: RivetEvent) => void) | null) {\n\t\tthis.#onopen = handler;\n\t}\n\n\tget onclose(): ((event: RivetCloseEvent) => void) | null {\n\t\treturn this.#onclose;\n\t}\n\tset onclose(handler: ((event: RivetCloseEvent) => void) | null) {\n\t\tthis.#onclose = handler;\n\t}\n\n\tget onerror(): ((event: RivetEvent) => void) | null {\n\t\treturn this.#onerror;\n\t}\n\tset onerror(handler: ((event: RivetEvent) => void) | null) {\n\t\tthis.#onerror = handler;\n\t}\n\n\tget onmessage(): ((event: RivetMessageEvent) => void) | null {\n\t\treturn this.#onmessage;\n\t}\n\tset onmessage(handler: ((event: RivetMessageEvent) => void) | null) {\n\t\tthis.#onmessage = handler;\n\t}\n}\n","import type {\n\tActorConfig as EngineActorConfig,\n\tRunnerConfig as EngineRunnerConfig,\n\tHibernatingWebSocketMetadata,\n} from \"@rivetkit/engine-runner\";\nimport { idToStr, Runner } from \"@rivetkit/engine-runner\";\nimport * as cbor from \"cbor-x\";\nimport type { Context as HonoContext } from \"hono\";\nimport { streamSSE } from \"hono/streaming\";\nimport { WSContext, type WSContextInit } from \"hono/ws\";\nimport invariant from \"invariant\";\nimport { type AnyConn, CONN_STATE_MANAGER_SYMBOL } from \"@/actor/conn/mod\";\nimport { lookupInRegistry } from \"@/actor/definition\";\nimport { KEYS } from \"@/actor/instance/kv\";\nimport { deserializeActorKey } from \"@/actor/keys\";\nimport { getValueLength } from \"@/actor/protocol/old\";\nimport { type ActorRouter, createActorRouter } from \"@/actor/router\";\nimport {\n\tparseWebSocketProtocols,\n\trouteWebSocket,\n\ttruncateRawWebSocketPathPrefix,\n\ttype UpgradeWebSocketArgs,\n} from \"@/actor/router-websocket-endpoints\";\nimport type { Client } from \"@/client/client\";\nimport {\n\tPATH_CONNECT,\n\tPATH_INSPECTOR_CONNECT,\n\tPATH_WEBSOCKET_BASE,\n\tPATH_WEBSOCKET_PREFIX,\n} from \"@/common/actor-router-consts\";\nimport { getLogger } from \"@/common/log\";\nimport type {\n\tRivetMessageEvent,\n\tUniversalWebSocket,\n} from \"@/common/websocket-interface\";\nimport {\n\ttype ActorDriver,\n\ttype AnyActorInstance,\n\tgetInitialActorKvState,\n\ttype ManagerDriver,\n} from \"@/driver-helpers/mod\";\nimport { buildActorNames, type RegistryConfig } from \"@/registry/config\";\nimport type { RunnerConfig } from \"@/registry/run-config\";\nimport { getEndpoint } from \"@/remote-manager-driver/api-utils\";\nimport {\n\ttype LongTimeoutHandle,\n\tpromiseWithResolvers,\n\tsetLongTimeout,\n\tstringifyError,\n} from \"@/utils\";\nimport { logger } from \"./log\";\n\nconst RUNNER_SSE_PING_INTERVAL = 1000;\n\n// Message ack deadline is 30s on the gateway, but we will ack more frequently\n// in order to minimize the message buffer size on the gateway and to give\n// generous breathing room for the timeout.\n//\n// See engine/packages/pegboard-gateway/src/shared_state.rs\n// (HWS_MESSAGE_ACK_TIMEOUT)\nconst CONN_MESSAGE_ACK_DEADLINE = 5_000;\n\n// Force saveState when cumulative message size reaches this threshold (0.5 MB)\n//\n// See engine/packages/pegboard-gateway/src/shared_state.rs\n// (HWS_MAX_PENDING_MSGS_SIZE_PER_REQ)\nconst CONN_BUFFERED_MESSAGE_SIZE_THRESHOLD = 500_000;\n\ninterface ActorHandler {\n\tactor?: AnyActorInstance;\n\tactorStartPromise?: ReturnType<typeof promiseWithResolvers<void>>;\n}\n\nexport type DriverContext = {};\n\nexport class EngineActorDriver implements ActorDriver {\n\t#registryConfig: RegistryConfig;\n\t#runConfig: RunnerConfig;\n\t#managerDriver: ManagerDriver;\n\t#inlineClient: Client<any>;\n\t#runner: Runner;\n\t#actors: Map<string, ActorHandler> = new Map();\n\t#actorRouter: ActorRouter;\n\t#version: number = 1; // Version for the runner protocol\n\t#alarmTimeout?: LongTimeoutHandle;\n\n\t#runnerStarted: PromiseWithResolvers<undefined> = promiseWithResolvers();\n\t#runnerStopped: PromiseWithResolvers<undefined> = promiseWithResolvers();\n\t#isRunnerStopped: boolean = false;\n\n\t// HACK: Track actor stop intent locally since the runner protocol doesn't\n\t// pass the stop reason to onActorStop. This will be fixed when the runner\n\t// protocol is updated to send the intent directly (see RVT-5284)\n\t#actorStopIntent: Map<string, \"sleep\" | \"destroy\"> = new Map();\n\n\t// Map of conn IDs to message index waiting to be persisted before sending\n\t// an ack\n\t//\n\t// serverMessageIndex is updated and pendingAck is flagged in needed in\n\t// onBeforePersistConnect, then the HWS ack message is sent in\n\t// onAfterPersistConn. This allows us to track what's about to be written\n\t// to storage to prevent race conditions with the serverMessageIndex being\n\t// updated while writing the existing state.\n\t//\n\t// bufferedMessageSize tracks the total bytes received since last persist\n\t// to force a saveState when threshold is reached. This is the amount of\n\t// data currently buffered on the gateway.\n\t#hwsMessageIndex = new Map<\n\t\tstring,\n\t\t{\n\t\t\tserverMessageIndex: number;\n\t\t\tbufferedMessageSize: number;\n\t\t\tpendingAckFromMessageIndex: boolean;\n\t\t\tpendingAckFromBufferSize: boolean;\n\t\t}\n\t>();\n\n\tconstructor(\n\t\tregistryConfig: RegistryConfig,\n\t\trunConfig: RunnerConfig,\n\t\tmanagerDriver: ManagerDriver,\n\t\tinlineClient: Client<any>,\n\t) {\n\t\tthis.#registryConfig = registryConfig;\n\t\tthis.#runConfig = runConfig;\n\t\tthis.#managerDriver = managerDriver;\n\t\tthis.#inlineClient = inlineClient;\n\n\t\t// HACK: Override inspector token (which are likely to be\n\t\t// removed later on) with token from x-rivet-token header\n\t\tconst token = runConfig.token;\n\t\tif (token && runConfig.inspector && runConfig.inspector.enabled) {\n\t\t\trunConfig.inspector.token = () => token;\n\t\t}\n\n\t\tthis.#actorRouter = createActorRouter(\n\t\t\trunConfig,\n\t\t\tthis,\n\t\t\tregistryConfig.test.enabled,\n\t\t);\n\n\t\t// Create runner configuration\n\t\tconst engineRunnerConfig: EngineRunnerConfig = {\n\t\t\tversion: this.#version,\n\t\t\tendpoint: getEndpoint(runConfig),\n\t\t\ttoken,\n\t\t\tnamespace: runConfig.namespace,\n\t\t\ttotalSlots: runConfig.totalSlots,\n\t\t\trunnerName: runConfig.runnerName,\n\t\t\trunnerKey: runConfig.runnerKey ?? crypto.randomUUID(),\n\t\t\tmetadata: {\n\t\t\t\tinspectorToken: this.#runConfig.inspector.token(),\n\t\t\t},\n\t\t\tprepopulateActorNames: buildActorNames(registryConfig),\n\t\t\tonConnected: () => {\n\t\t\t\tthis.#runnerStarted.resolve(undefined);\n\t\t\t},\n\t\t\tonDisconnected: (_code, _reason) => {},\n\t\t\tonShutdown: () => {\n\t\t\t\tthis.#runnerStopped.resolve(undefined);\n\t\t\t\tthis.#isRunnerStopped = true;\n\t\t\t},\n\t\t\tfetch: this.#runnerFetch.bind(this),\n\t\t\twebsocket: this.#runnerWebSocket.bind(this),\n\t\t\thibernatableWebSocket: {\n\t\t\t\tcanHibernate: this.#hwsCanHibernate.bind(this),\n\t\t\t},\n\t\t\tonActorStart: this.#runnerOnActorStart.bind(this),\n\t\t\tonActorStop: this.#runnerOnActorStop.bind(this),\n\t\t\tlogger: getLogger(\"engine-runner\"),\n\t\t};\n\n\t\t// Create and start runner\n\t\tthis.#runner = new Runner(engineRunnerConfig);\n\t\tthis.#runner.start();\n\t\tlogger().debug({\n\t\t\tmsg: \"engine runner started\",\n\t\t\tendpoint: runConfig.endpoint,\n\t\t\tnamespace: runConfig.namespace,\n\t\t\trunnerName: runConfig.runnerName,\n\t\t});\n\t}\n\n\tgetExtraActorLogParams(): Record<string, string> {\n\t\treturn { runnerId: this.#runner.runnerId ?? \"-\" };\n\t}\n\n\tasync #loadActorHandler(actorId: string): Promise<ActorHandler> {\n\t\t// Check if actor is already loaded\n\t\tconst handler = this.#actors.get(actorId);\n\t\tif (!handler)\n\t\t\tthrow new Error(`Actor handler does not exist ${actorId}`);\n\t\tif (handler.actorStartPromise) await handler.actorStartPromise.promise;\n\t\tif (!handler.actor) throw new Error(\"Actor should be loaded\");\n\t\treturn handler;\n\t}\n\n\tgetContext(actorId: string): DriverContext {\n\t\treturn {};\n\t}\n\n\tasync setAlarm(actor: AnyActorInstance, timestamp: number): Promise<void> {\n\t\t// Clear prev timeout\n\t\tif (this.#alarmTimeout) {\n\t\t\tthis.#alarmTimeout.abort();\n\t\t\tthis.#alarmTimeout = undefined;\n\t\t}\n\n\t\t// Set alarm\n\t\tconst delay = Math.max(0, timestamp - Date.now());\n\t\tthis.#alarmTimeout = setLongTimeout(() => {\n\t\t\tactor.onAlarm();\n\t\t\tthis.#alarmTimeout = undefined;\n\t\t}, delay);\n\n\t\t// TODO: This call may not be needed on ActorInstance.start, but it does help ensure that the local state is synced with the alarm state\n\t\t// Set alarm on Rivet\n\t\t//\n\t\t// This does not call an \"alarm\" event like Durable Objects.\n\t\t// Instead, it just wakes the actor on the alarm (if not\n\t\t// already awake).\n\t\t//\n\t\t// onAlarm is automatically called on `ActorInstance.start` when waking\n\t\t// again.\n\t\tthis.#runner.setAlarm(actor.id, timestamp);\n\t}\n\n\tasync getDatabase(_actorId: string): Promise<unknown | undefined> {\n\t\treturn undefined;\n\t}\n\n\t// MARK: - Batch KV operations\n\tasync kvBatchPut(\n\t\tactorId: string,\n\t\tentries: [Uint8Array, Uint8Array][],\n\t): Promise<void> {\n\t\tawait this.#runner.kvPut(actorId, entries);\n\t}\n\n\tasync kvBatchGet(\n\t\tactorId: string,\n\t\tkeys: Uint8Array[],\n\t): Promise<(Uint8Array | null)[]> {\n\t\treturn await this.#runner.kvGet(actorId, keys);\n\t}\n\n\tasync kvBatchDelete(actorId: string, keys: Uint8Array[]): Promise<void> {\n\t\tawait this.#runner.kvDelete(actorId, keys);\n\t}\n\n\tasync kvList(actorId: string): Promise<Uint8Array[]> {\n\t\tconst entries = await this.#runner.kvListPrefix(\n\t\t\tactorId,\n\t\t\tnew Uint8Array(),\n\t\t);\n\t\tconst keys = entries.map(([key]) => key);\n\t\tlogger().info({\n\t\t\tmsg: \"kvList called\",\n\t\t\tactorId,\n\t\t\tkeysCount: keys.length,\n\t\t\tkeys: keys.map((k) => new TextDecoder().decode(k)),\n\t\t});\n\t\treturn keys;\n\t}\n\n\tasync kvListPrefix(\n\t\tactorId: string,\n\t\tprefix: Uint8Array,\n\t): Promise<[Uint8Array, Uint8Array][]> {\n\t\tconst result = await this.#runner.kvListPrefix(actorId, prefix);\n\t\tlogger().info({\n\t\t\tmsg: \"kvListPrefix called\",\n\t\t\tactorId,\n\t\t\tprefixStr: new TextDecoder().decode(prefix),\n\t\t\tentriesCount: result.length,\n\t\t\tkeys: result.map(([key]) => new TextDecoder().decode(key)),\n\t\t});\n\t\treturn result;\n\t}\n\n\t// MARK: - Actor Lifecycle\n\tasync loadActor(actorId: string): Promise<AnyActorInstance> {\n\t\tconst handler = await this.#loadActorHandler(actorId);\n\t\tif (!handler.actor) throw new Error(`Actor ${actorId} failed to load`);\n\t\treturn handler.actor;\n\t}\n\n\tstartSleep(actorId: string) {\n\t\t// HACK: Track intent for onActorStop (see RVT-5284)\n\t\tthis.#actorStopIntent.set(actorId, \"sleep\");\n\t\tthis.#runner.sleepActor(actorId);\n\t}\n\n\tstartDestroy(actorId: string) {\n\t\t// HACK: Track intent for onActorStop (see RVT-5284)\n\t\tthis.#actorStopIntent.set(actorId, \"destroy\");\n\t\tthis.#runner.stopActor(actorId);\n\t}\n\n\tasync shutdownRunner(immediate: boolean): Promise<void> {\n\t\tlogger().info({ msg: \"stopping engine actor driver\", immediate });\n\n\t\t// TODO: We need to update the runner to have a draining state so:\n\t\t// 1. Send ToServerDraining\n\t\t//\t\t- This causes Pegboard to stop allocating actors to this runner\n\t\t// 2. Pegboard sends ToClientStopActor for all actors on this runner which handles the graceful migration of each actor independently\n\t\t// 3. Send ToServerStopping once all actors have successfully stopped\n\t\t//\n\t\t// What's happening right now is:\n\t\t// 1. All actors enter stopped state\n\t\t// 2. Actors still respond to requests because only RivetKit knows it's\n\t\t// stopping, this causes all requests to issue errors that the actor is\n\t\t// stopping. (This will NOT return a 503 bc the runner has no idea the\n\t\t// actors are stopping.)\n\t\t// 3. Once the last actor stops, then the runner finally stops + actors\n\t\t// reschedule\n\t\t//\n\t\t// This means that:\n\t\t// - All actors on this runner are bricked until the slowest onStop finishes\n\t\t// - Guard will not gracefully handle requests bc it's not receiving a 503\n\t\t// - Actors can still be scheduled to this runner while the other\n\t\t// actors are stopping, meaning that those actors will NOT get onStop\n\t\t// and will potentiall corrupt their state\n\t\t//\n\t\t// HACK: Stop all actors to allow state to be saved\n\t\t// NOTE: onStop is only supposed to be called by the runner, we're\n\t\t// abusing it here\n\t\tlogger().debug({\n\t\t\tmsg: \"stopping all actors before shutdown\",\n\t\t\tactorCount: this.#actors.size,\n\t\t});\n\t\tconst stopPromises: Promise<void>[] = [];\n\t\tfor (const [_actorId, handler] of this.#actors.entries()) {\n\t\t\tif (handler.actor) {\n\t\t\t\tstopPromises.push(\n\t\t\t\t\thandler.actor.onStop(\"sleep\").catch((err) => {\n\t\t\t\t\t\thandler.actor?.rLog.error({\n\t\t\t\t\t\t\tmsg: \"onStop errored\",\n\t\t\t\t\t\t\terror: stringifyError(err),\n\t\t\t\t\t\t});\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tawait Promise.all(stopPromises);\n\t\tlogger().debug({ msg: \"all actors stopped\" });\n\n\t\tawait this.#runner.shutdown(immediate);\n\t}\n\n\tasync serverlessHandleStart(c: HonoContext): Promise<Response> {\n\t\treturn streamSSE(c, async (stream) => {\n\t\t\t// NOTE: onAbort does not work reliably\n\t\t\tstream.onAbort(() => {});\n\t\t\tc.req.raw.signal.addEventListener(\"abort\", () => {\n\t\t\t\tlogger().debug(\"SSE aborted, shutting down runner\");\n\n\t\t\t\t// We cannot assume that the request will always be closed gracefully by Rivet. We always proceed with a graceful shutdown in case the request was terminated for any other reason.\n\t\t\t\t//\n\t\t\t\t// If we did not use a graceful shutdown, the runner would\n\t\t\t\tthis.shutdownRunner(false);\n\t\t\t});\n\n\t\t\tawait this.#runnerStarted.promise;\n\n\t\t\t// Runner id should be set if the runner started\n\t\t\tconst payload = this.#runner.getServerlessInitPacket();\n\t\t\tinvariant(payload, \"runnerId not set\");\n\t\t\tawait stream.writeSSE({ data: payload });\n\n\t\t\t// Send ping every second to keep the connection alive\n\t\t\twhile (true) {\n\t\t\t\tif (this.#isRunnerStopped) {\n\t\t\t\t\tlogger().debug({\n\t\t\t\t\t\tmsg: \"runner is stopped\",\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (stream.closed || stream.aborted) {\n\t\t\t\t\tlogger().debug({\n\t\t\t\t\t\tmsg: \"runner sse stream closed\",\n\t\t\t\t\t\tclosed: stream.closed,\n\t\t\t\t\t\taborted: stream.aborted,\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tawait stream.writeSSE({ event: \"ping\", data: \"\" });\n\t\t\t\tawait stream.sleep(RUNNER_SSE_PING_INTERVAL);\n\t\t\t}\n\n\t\t\t// Wait for the runner to stop if the SSE stream aborted early for any reason\n\t\t\tawait this.#runnerStopped.promise;\n\t\t});\n\t}\n\n\tasync #runnerOnActorStart(\n\t\tactorId: string,\n\t\tgeneration: number,\n\t\tactorConfig: EngineActorConfig,\n\t): Promise<void> {\n\t\tlogger().debug({\n\t\t\tmsg: \"runner actor starting\",\n\t\t\tactorId,\n\t\t\tname: actorConfig.name,\n\t\t\tkey: actorConfig.key,\n\t\t\tgeneration,\n\t\t});\n\n\t\t// Deserialize input\n\t\tlet input: any;\n\t\tif (actorConfig.input) {\n\t\t\tinput = cbor.decode(actorConfig.input);\n\t\t}\n\n\t\t// Get or create handler\n\t\tlet handler = this.#actors.get(actorId);\n\t\tif (!handler) {\n\t\t\t// IMPORTANT: We must set the handler in the map synchronously before doing any\n\t\t\t// async operations to avoid race conditions where multiple calls might try to\n\t\t\t// create the same handler simultaneously.\n\t\t\thandler = {\n\t\t\t\tactorStartPromise: promiseWithResolvers(),\n\t\t\t};\n\t\t\tthis.#actors.set(actorId, handler);\n\t\t}\n\n\t\tconst name = actorConfig.name as string;\n\t\tinvariant(actorConfig.key, \"actor should have a key\");\n\t\tconst key = deserializeActorKey(actorConfig.key);\n\n\t\t// Initialize storage\n\t\tconst [persistDataBuffer] = await this.#runner.kvGet(actorId, [\n\t\t\tKEYS.PERSIST_DATA,\n\t\t]);\n\t\tif (persistDataBuffer === null) {\n\t\t\tconst initialKvState = getInitialActorKvState(input);\n\t\t\tawait this.#runner.kvPut(actorId, initialKvState);\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"initialized persist data for new actor\",\n\t\t\t\tactorId,\n\t\t\t});\n\t\t} else {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"found existing persist data for actor\",\n\t\t\t\tactorId,\n\t\t\t\tdataSize: persistDataBuffer.byteLength,\n\t\t\t});\n\t\t}\n\n\t\t// Create actor instance\n\t\tconst definition = lookupInRegistry(\n\t\t\tthis.#registryConfig,\n\t\t\tactorConfig.name,\n\t\t);\n\t\thandler.actor = definition.instantiate();\n\n\t\t// Start actor\n\t\tawait handler.actor.start(\n\t\t\tthis,\n\t\t\tthis.#inlineClient,\n\t\t\tactorId,\n\t\t\tname,\n\t\t\tkey,\n\t\t\t\"unknown\", // TODO: Add regions\n\t\t);\n\n\t\tlogger().debug({ msg: \"runner actor started\", actorId, name, key });\n\t}\n\n\tasync #runnerOnActorStop(\n\t\tactorId: string,\n\t\tgeneration: number,\n\t): Promise<void> {\n\t\tlogger().debug({ msg: \"runner actor stopping\", actorId, generation });\n\n\t\t// HACK: Retrieve the stop intent we tracked locally (see RVT-5284)\n\t\t// Default to \"sleep\" if no intent was recorded (e.g., if the runner\n\t\t// initiated the stop)\n\t\t//\n\t\t// TODO: This will not work if the actor is destroyed from the API\n\t\t// correctly. Currently, it will use the sleep intent, but it's\n\t\t// actually a destroy intent.\n\t\tconst reason = this.#actorStopIntent.get(actorId) ?? \"sleep\";\n\t\tthis.#actorStopIntent.delete(actorId);\n\n\t\tconst handler = this.#actors.get(actorId);\n\t\tif (handler?.actor) {\n\t\t\ttry {\n\t\t\t\tawait handler.actor.onStop(reason);\n\t\t\t} catch (err) {\n\t\t\t\tlogger().error({\n\t\t\t\t\tmsg: \"error in onStop, proceeding with removing actor\",\n\t\t\t\t\terr: stringifyError(err),\n\t\t\t\t});\n\t\t\t}\n\t\t\tthis.#actors.delete(actorId);\n\t\t}\n\n\t\tlogger().debug({ msg: \"runner actor stopped\", actorId, reason });\n\t}\n\n\t// MARK: - Runner Networking\n\tasync #runnerFetch(\n\t\t_runner: Runner,\n\t\tactorId: string,\n\t\t_gatewayIdBuf: ArrayBuffer,\n\t\t_requestIdBuf: ArrayBuffer,\n\t\trequest: Request,\n\t): Promise<Response> {\n\t\tlogger().debug({\n\t\t\tmsg: \"runner fetch\",\n\t\t\tactorId,\n\t\t\turl: request.url,\n\t\t\tmethod: request.method,\n\t\t});\n\t\treturn await this.#actorRouter.fetch(request, { actorId });\n\t}\n\n\tasync #runnerWebSocket(\n\t\t_runner: Runner,\n\t\tactorId: string,\n\t\twebsocketRaw: any,\n\t\tgatewayIdBuf: ArrayBuffer,\n\t\trequestIdBuf: ArrayBuffer,\n\t\trequest: Request,\n\t\trequestPath: string,\n\t\trequestHeaders: Record<string, string>,\n\t\tisHibernatable: boolean,\n\t\tisRestoringHibernatable: boolean,\n\t): Promise<void> {\n\t\tconst websocket = websocketRaw as UniversalWebSocket;\n\n\t\t// Add a unique ID to track this WebSocket object\n\t\tconst wsUniqueId = `ws_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n\t\t(websocket as any).__rivet_ws_id = wsUniqueId;\n\n\t\tlogger().debug({\n\t\t\tmsg: \"runner websocket\",\n\t\t\tactorId,\n\t\t\turl: request.url,\n\t\t\tisRestoringHibernatable,\n\t\t\twebsocketObjectId: websocketRaw\n\t\t\t\t? Object.prototype.toString.call(websocketRaw)\n\t\t\t\t: \"null\",\n\t\t\twebsocketType: websocketRaw?.constructor?.name,\n\t\t\twsUniqueId,\n\t\t\twebsocketProps: websocketRaw\n\t\t\t\t? Object.keys(websocketRaw).join(\", \")\n\t\t\t\t: \"null\",\n\t\t});\n\n\t\t// Parse configuration from Sec-WebSocket-Protocol header (optional for path-based routing)\n\t\tconst protocols = request.headers.get(\"sec-websocket-protocol\");\n\t\tconst { encoding, connParams } = parseWebSocketProtocols(protocols);\n\n\t\t// Fetch WS handler\n\t\t//\n\t\t// We store the promise since we need to add WebSocket event listeners immediately that will wait for the promise to resolve\n\t\tlet wsHandler: UpgradeWebSocketArgs;\n\t\ttry {\n\t\t\twsHandler = await routeWebSocket(\n\t\t\t\trequest,\n\t\t\t\trequestPath,\n\t\t\t\trequestHeaders,\n\t\t\t\tthis.#runConfig,\n\t\t\t\tthis,\n\t\t\t\tactorId,\n\t\t\t\tencoding,\n\t\t\t\tconnParams,\n\t\t\t\tgatewayIdBuf,\n\t\t\t\trequestIdBuf,\n\t\t\t\tisHibernatable,\n\t\t\t\tisRestoringHibernatable,\n\t\t\t);\n\t\t} catch (err) {\n\t\t\tlogger().error({ msg: \"building websocket handlers errored\", err });\n\t\t\twebsocketRaw.close(1011, \"ws.route_error\");\n\t\t\treturn;\n\t\t}\n\n\t\t// Connect the Hono WS hook to the adapter\n\t\t//\n\t\t// We need to assign to `raw` in order for WSContext to expose it on\n\t\t// `ws.raw`\n\t\t(websocket as WSContextInit).raw = websocket;\n\t\tconst wsContext = new WSContext(websocket);\n\n\t\t// Get connection and actor from wsHandler (may be undefined for inspector endpoint)\n\t\tconst conn = wsHandler.conn;\n\t\tconst actor = wsHandler.actor;\n\t\tconst connStateManager = conn?.[CONN_STATE_MANAGER_SYMBOL];\n\n\t\t// Bind event listeners to Hono WebSocket handlers\n\t\t//\n\t\t// We update the HWS data after calling handlers in order to ensure\n\t\t// that the handler ran successfully. By doing this, we ensure at least\n\t\t// once delivery of events to the event handlers.\n\n\t\t// Log when attaching event listeners\n\t\tlogger().debug({\n\t\t\tmsg: \"attaching websocket event listeners\",\n\t\t\tactorId,\n\t\t\tconnId: conn?.id,\n\t\t\twsUniqueId: (websocket as any).__rivet_ws_id,\n\t\t\tisRestoringHibernatable,\n\t\t\twebsocketType: websocket?.constructor?.name,\n\t\t});\n\n\t\tif (isRestoringHibernatable) {\n\t\t\twsHandler.onRestore?.(wsContext);\n\t\t}\n\n\t\twebsocket.addEventListener(\"open\", (event) => {\n\t\t\twsHandler.onOpen(event, wsContext);\n\t\t});\n\n\t\twebsocket.addEventListener(\"message\", (event: RivetMessageEvent) => {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"websocket message event listener triggered\",\n\t\t\t\tconnId: conn?.id,\n\t\t\t\tactorId: actor?.id,\n\t\t\t\tmessageIndex: event.rivetMessageIndex,\n\t\t\t\thasWsHandler: !!wsHandler,\n\t\t\t\thasOnMessage: !!wsHandler?.onMessage,\n\t\t\t\tactorIsStopping: actor?.isStopping,\n\t\t\t\twebsocketType: websocket?.constructor?.name,\n\t\t\t\twsUniqueId: (websocket as any).__rivet_ws_id,\n\t\t\t\teventTargetWsId: (event.target as any)?.__rivet_ws_id,\n\t\t\t});\n\n\t\t\t// Check if actor is stopping - if so, don't process new messages.\n\t\t\t// These messages will be reprocessed when the actor wakes up from hibernation.\n\t\t\t// TODO: This will never retransmit the socket and the socket will close\n\t\t\tif (actor?.isStopping) {\n\t\t\t\tlogger().debug({\n\t\t\t\t\tmsg: \"ignoring ws message, actor is stopping\",\n\t\t\t\t\tconnId: conn?.id,\n\t\t\t\t\tactorId: actor?.id,\n\t\t\t\t\tmessageIndex: event.rivetMessageIndex,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Process message\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"calling wsHandler.onMessage\",\n\t\t\t\tconnId: conn?.id,\n\t\t\t\tmessageIndex: event.rivetMessageIndex,\n\t\t\t});\n\t\t\twsHandler.onMessage(event, wsContext);\n\n\t\t\t// Persist message index for hibernatable connections\n\t\t\tconst hibernate = connStateManager?.hibernatableData;\n\n\t\t\tif (hibernate && conn && actor) {\n\t\t\t\tinvariant(\n\t\t\t\t\ttypeof event.rivetMessageIndex === \"number\",\n\t\t\t\t\t\"missing event.rivetMessageIndex\",\n\t\t\t\t);\n\n\t\t\t\t// Persist message index\n\t\t\t\tconst previousMsgIndex = hibernate.serverMessageIndex;\n\t\t\t\thibernate.serverMessageIndex = event.rivetMessageIndex;\n\t\t\t\tlogger().info({\n\t\t\t\t\tmsg: \"persisting message index\",\n\t\t\t\t\tconnId: conn.id,\n\t\t\t\t\tpreviousMsgIndex,\n\t\t\t\t\tnewMsgIndex: event.rivetMessageIndex,\n\t\t\t\t});\n\n\t\t\t\t// Calculate message size and track cumulative size\n\t\t\t\tconst entry = this.#hwsMessageIndex.get(conn.id);\n\t\t\t\tif (entry) {\n\t\t\t\t\t// Track message length\n\t\t\t\t\tconst messageLength = getValueLength(event.data);\n\t\t\t\t\tentry.bufferedMessageSize += messageLength;\n\n\t\t\t\t\tif (\n\t\t\t\t\t\tentry.bufferedMessageSize >=\n\t\t\t\t\t\tCONN_BUFFERED_MESSAGE_SIZE_THRESHOLD\n\t\t\t\t\t) {\n\t\t\t\t\t\t// Reset buffered message size immeidatley (instead\n\t\t\t\t\t\t// of waiting for onAfterPersistConn) since we may\n\t\t\t\t\t\t// receive more messages before onAfterPersistConn\n\t\t\t\t\t\t// is called, which would called saveState\n\t\t\t\t\t\t// immediate multiple times\n\t\t\t\t\t\tentry.bufferedMessageSize = 0;\n\t\t\t\t\t\tentry.pendingAckFromBufferSize = true;\n\n\t\t\t\t\t\t// Save state immediately if approaching buffer threshold\n\t\t\t\t\t\tactor.stateManager.saveState({\n\t\t\t\t\t\t\timmediate: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Save message index. The maxWait is set to the ack deadline\n\t\t\t\t\t\t// since we ack the message immediately after persisting the index.\n\t\t\t\t\t\t// If cumulative size exceeds threshold, force immediate persist.\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// This will call EngineActorDriver.onAfterPersistConn after\n\t\t\t\t\t\t// persist to send the ack to the gateway.\n\t\t\t\t\t\tactor.stateManager.saveState({\n\t\t\t\t\t\t\tmaxWait: CONN_MESSAGE_ACK_DEADLINE,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Fallback if entry missing\n\t\t\t\t\tactor.stateManager.saveState({\n\t\t\t\t\t\tmaxWait: CONN_MESSAGE_ACK_DEADLINE,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\twebsocket.addEventListener(\"close\", (event) => {\n\t\t\twsHandler.onClose(event, wsContext);\n\n\t\t\t// NOTE: Persisted connection is removed when `conn.disconnect`\n\t\t\t// is called by the WebSocket route\n\t\t});\n\n\t\twebsocket.addEventListener(\"error\", (event) => {\n\t\t\twsHandler.onError(event, wsContext);\n\t\t});\n\n\t\t// Log event listener attachment for restored connections\n\t\tif (isRestoringHibernatable) {\n\t\t\tlogger().info({\n\t\t\t\tmsg: \"event listeners attached to restored websocket\",\n\t\t\t\tactorId,\n\t\t\t\tconnId: conn?.id,\n\t\t\t\tgatewayId: idToStr(gatewayIdBuf),\n\t\t\t\trequestId: idToStr(requestIdBuf),\n\t\t\t\twebsocketType: websocket?.constructor?.name,\n\t\t\t\thasMessageListener: !!websocket.addEventListener,\n\t\t\t});\n\t\t}\n\t}\n\n\t// MARK: - Hibernating WebSockets\n\t#hwsCanHibernate(\n\t\tactorId: string,\n\t\tgatewayId: ArrayBuffer,\n\t\trequestId: ArrayBuffer,\n\t\trequest: Request,\n\t): boolean {\n\t\tconst url = new URL(request.url);\n\t\tconst path = url.pathname;\n\n\t\t// Get actor instance from runner to access actor name\n\t\tconst actorInstance = this.#runner.getActor(actorId);\n\t\tif (!actorInstance) {\n\t\t\tlogger().warn({\n\t\t\t\tmsg: \"actor not found in #hwsCanHibernate\",\n\t\t\t\tactorId,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\n\t\t// Load actor handler to access persisted data\n\t\tconst handler = this.#actors.get(actorId);\n\t\tif (!handler) {\n\t\t\tlogger().warn({\n\t\t\t\tmsg: \"actor handler not found in #hwsCanHibernate\",\n\t\t\t\tactorId,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t\tif (!handler.actor) {\n\t\t\tlogger().warn({\n\t\t\t\tmsg: \"actor not found in #hwsCanHibernate\",\n\t\t\t\tactorId,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\n\t\t// Determine configuration for new WS\n\t\tlogger().debug({\n\t\t\tmsg: \"no existing hibernatable websocket found\",\n\t\t\tgatewayId: idToStr(gatewayId),\n\t\t\trequestId: idToStr(requestId),\n\t\t});\n\t\tif (path === PATH_CONNECT) {\n\t\t\treturn true;\n\t\t} else if (\n\t\t\tpath === PATH_WEBSOCKET_BASE ||\n\t\t\tpath.startsWith(PATH_WEBSOCKET_PREFIX)\n\t\t) {\n\t\t\t// Find actor config\n\t\t\tconst definition = lookupInRegistry(\n\t\t\t\tthis.#registryConfig,\n\t\t\t\tactorInstance.config.name,\n\t\t\t);\n\n\t\t\t// Check if can hibernate\n\t\t\tconst canHibernateWebSocket =\n\t\t\t\tdefinition.config.options?.canHibernateWebSocket;\n\t\t\tif (canHibernateWebSocket === true) {\n\t\t\t\treturn true;\n\t\t\t} else if (typeof canHibernateWebSocket === \"function\") {\n\t\t\t\ttry {\n\t\t\t\t\t// Truncate the path to match the behavior on onRawWebSocket\n\t\t\t\t\tconst newPath = truncateRawWebSocketPathPrefix(\n\t\t\t\t\t\turl.pathname,\n\t\t\t\t\t);\n\t\t\t\t\tconst truncatedRequest = new Request(\n\t\t\t\t\t\t`http://actor${newPath}`,\n\t\t\t\t\t\trequest,\n\t\t\t\t\t);\n\n\t\t\t\t\tconst canHibernate =\n\t\t\t\t\t\tcanHibernateWebSocket(truncatedRequest);\n\t\t\t\t\treturn canHibernate;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger().error({\n\t\t\t\t\t\tmsg: \"error calling canHibernateWebSocket\",\n\t\t\t\t\t\terror,\n\t\t\t\t\t});\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} else if (path === PATH_INSPECTOR_CONNECT) {\n\t\t\treturn false;\n\t\t} else {\n\t\t\tlogger().warn({\n\t\t\t\tmsg: \"unexpected path for getActorHibernationConfig\",\n\t\t\t\tpath,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tasync #hwsLoadAll(\n\t\tactorId: string,\n\t): Promise<HibernatingWebSocketMetadata[]> {\n\t\tconst actor = await this.loadActor(actorId);\n\t\treturn actor.conns\n\t\t\t.values()\n\t\t\t.map((conn) => {\n\t\t\t\tconst connStateManager = conn[CONN_STATE_MANAGER_SYMBOL];\n\t\t\t\tconst hibernatable = connStateManager.hibernatableData;\n\t\t\t\tif (!hibernatable) return undefined;\n\t\t\t\treturn {\n\t\t\t\t\tgatewayId: hibernatable.gatewayId,\n\t\t\t\t\trequestId: hibernatable.requestId,\n\t\t\t\t\tserverMessageIndex: hibernatable.serverMessageIndex,\n\t\t\t\t\tclientMessageIndex: hibernatable.clientMessageIndex,\n\t\t\t\t\tpath: hibernatable.requestPath,\n\t\t\t\t\theaders: hibernatable.requestHeaders,\n\t\t\t\t} satisfies HibernatingWebSocketMetadata;\n\t\t\t})\n\t\t\t.filter((x) => x !== undefined)\n\t\t\t.toArray();\n\t}\n\n\tasync onBeforeActorStart(actor: AnyActorInstance): Promise<void> {\n\t\t// Resolve promise if waiting\n\t\tconst handler = this.#actors.get(actor.id);\n\t\tinvariant(handler, \"missing actor handler in onBeforeActorReady\");\n\t\thandler.actorStartPromise?.resolve();\n\t\thandler.actorStartPromise = undefined;\n\n\t\t// Restore hibernating requests\n\t\tconst metaEntries = await this.#hwsLoadAll(actor.id);\n\t\tawait this.#runner.restoreHibernatingRequests(actor.id, metaEntries);\n\t}\n\n\tonCreateConn(conn: AnyConn) {\n\t\tconst hibernatable = conn[CONN_STATE_MANAGER_SYMBOL].hibernatableData;\n\t\tif (!hibernatable) return;\n\n\t\tthis.#hwsMessageIndex.set(conn.id, {\n\t\t\tserverMessageIndex: hibernatable.serverMessageIndex,\n\t\t\tbufferedMessageSize: 0,\n\t\t\tpendingAckFromMessageIndex: false,\n\t\t\tpendingAckFromBufferSize: false,\n\t\t});\n\n\t\tlogger().debug({\n\t\t\tmsg: \"created #hwsMessageIndex entry\",\n\t\t\tconnId: conn.id,\n\t\t\tserverMessageIndex: hibernatable.serverMessageIndex,\n\t\t});\n\t}\n\n\tonDestroyConn(conn: AnyConn) {\n\t\tthis.#hwsMessageIndex.delete(conn.id);\n\n\t\tlogger().debug({\n\t\t\tmsg: \"removed #hwsMessageIndex entry\",\n\t\t\tconnId: conn.id,\n\t\t});\n\t}\n\n\tonBeforePersistConn(conn: AnyConn) {\n\t\tconst stateManager = conn[CONN_STATE_MANAGER_SYMBOL];\n\t\tconst hibernatable = stateManager.hibernatableDataOrError();\n\n\t\tconst entry = this.#hwsMessageIndex.get(conn.id);\n\t\tif (!entry) {\n\t\t\tlogger().warn({\n\t\t\t\tmsg: \"missing EngineActorDriver.#hwsMessageIndex entry for conn\",\n\t\t\t\tconnId: conn.id,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\t// There is a newer message index\n\t\tentry.pendingAckFromMessageIndex =\n\t\t\thibernatable.serverMessageIndex > entry.serverMessageIndex;\n\t\tentry.serverMessageIndex = hibernatable.serverMessageIndex;\n\t}\n\n\tonAfterPersistConn(conn: AnyConn) {\n\t\tconst stateManager = conn[CONN_STATE_MANAGER_SYMBOL];\n\t\tconst hibernatable = stateManager.hibernatableDataOrError();\n\n\t\tconst entry = this.#hwsMessageIndex.get(conn.id);\n\t\tif (!entry) {\n\t\t\tlogger().warn({\n\t\t\t\tmsg: \"missing EngineActorDriver.#hwsMessageIndex entry for conn\",\n\t\t\t\tconnId: conn.id,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\t// Ack entry\n\t\tif (\n\t\t\tentry.pendingAckFromMessageIndex ||\n\t\t\tentry.pendingAckFromBufferSize\n\t\t) {\n\t\t\tthis.#runner.sendHibernatableWebSocketMessageAck(\n\t\t\t\thibernatable.gatewayId,\n\t\t\t\thibernatable.requestId,\n\t\t\t\tentry.serverMessageIndex,\n\t\t\t);\n\t\t\tentry.pendingAckFromMessageIndex = false;\n\t\t\tentry.pendingAckFromBufferSize = false;\n\t\t\tentry.bufferedMessageSize = 0;\n\t\t}\n\t}\n}\n","import { getLogger } from \"@/common/log\";\n\nexport function logger() {\n\treturn getLogger(\"driver-engine\");\n}\n","import type { Client } from \"@/client/client\";\nimport type { ManagerDriver } from \"@/manager/driver\";\nimport type { RegistryConfig } from \"@/registry/config\";\nimport type { DriverConfig, RunnerConfig } from \"@/registry/run-config\";\nimport { RemoteManagerDriver } from \"@/remote-manager-driver/mod\";\nimport { EngineActorDriver } from \"./actor-driver\";\n\nexport { EngineActorDriver } from \"./actor-driver\";\nexport {\n\ttype EngineConfig as Config,\n\ttype EngineConfigInput as InputConfig,\n\tEngingConfigSchema as ConfigSchema,\n} from \"./config\";\n\nexport function createEngineDriver(): DriverConfig {\n\treturn {\n\t\tname: \"engine\",\n\t\tmanager: (_registryConfig, runConfig) => {\n\t\t\treturn new RemoteManagerDriver(runConfig);\n\t\t},\n\t\tactor: (\n\t\t\tregistryConfig: RegistryConfig,\n\t\t\trunConfig: RunnerConfig,\n\t\t\tmanagerDriver: ManagerDriver,\n\t\t\tinlineClient: Client<any>,\n\t\t) => {\n\t\t\treturn new EngineActorDriver(\n\t\t\t\tregistryConfig,\n\t\t\t\trunConfig,\n\t\t\t\tmanagerDriver,\n\t\t\t\tinlineClient,\n\t\t\t);\n\t\t},\n\t};\n}\n","import { createRequire } from \"node:module\";\n\n// Global variables for Node.js modules.\n//\n// We use synchronous require() instead of async import() for Node.js module loading because:\n// 1. These modules are only needed in Node.js environments (not browser/edge)\n// 2. registry.start() cannot be async and needs immediate access to Node modules\n// 3. The setup process must be synchronous to avoid breaking the API\n//\n// Biome only allows imports of node modules in this file in order to ensure\n// we're forcing the use of dynamic imports.\nlet nodeCrypto: typeof import(\"node:crypto\") | undefined;\nlet nodeFsSync: typeof import(\"node:fs\") | undefined;\nlet nodeFs: typeof import(\"node:fs/promises\") | undefined;\nlet nodePath: typeof import(\"node:path\") | undefined;\nlet nodeOs: typeof import(\"node:os\") | undefined;\nlet nodeChildProcess: typeof import(\"node:child_process\") | undefined;\nlet nodeStream: typeof import(\"node:stream/promises\") | undefined;\n\nlet hasImportedDependencies = false;\n\n// Helper to get a require function that works in both CommonJS and ESM.\n// We use require() instead of await import() because registry.start() cannot\n// be async and needs immediate access to Node.js modules during setup.\nfunction getRequireFn() {\n\t// TODO: This causes issues in tsup\n\t// CommonJS context - use global require\n\t// if (typeof require !== \"undefined\") {\n\t// \tconsole.log(\"existing require\");\n\t// \treturn require;\n\t// }\n\n\t// ESM context - use createRequire with import.meta.url\n\treturn createRequire(import.meta.url);\n}\n\n/**\n * Dynamically imports all required Node.js dependencies. We do this early in a\n * single function call in order to surface errors early.\n *\n * This function is idempotent and will only import once.\n *\n * @throws Error if Node.js modules are not available (e.g., in browser/edge environments)\n */\nexport function importNodeDependencies(): void {\n\t// Check if already loaded\n\tif (hasImportedDependencies) return;\n\n\ttry {\n\t\t// Get a require function that works in both CommonJS and ESM\n\t\tconst requireFn = getRequireFn();\n\n\t\t// Use requireFn with webpack ignore comment to prevent bundling\n\t\tnodeCrypto = requireFn(/* webpackIgnore: true */ \"node:crypto\");\n\t\tnodeFsSync = requireFn(/* webpackIgnore: true */ \"node:fs\");\n\t\tnodeFs = requireFn(/* webpackIgnore: true */ \"node:fs/promises\");\n\t\tnodePath = requireFn(/* webpackIgnore: true */ \"node:path\");\n\t\tnodeOs = requireFn(/* webpackIgnore: true */ \"node:os\");\n\t\tnodeChildProcess = requireFn(\n\t\t\t/* webpackIgnore: true */ \"node:child_process\",\n\t\t);\n\t\tnodeStream = requireFn(\n\t\t\t/* webpackIgnore: true */ \"node:stream/promises\",\n\t\t);\n\n\t\thasImportedDependencies = true;\n\t} catch (err) {\n\t\tconsole.warn(\n\t\t\t\"Node.js modules not available, file system driver will not work\",\n\t\t\terr,\n\t\t);\n\t\tthrow err;\n\t}\n}\n\n/**\n * Gets the Node.js crypto module.\n * @throws Error if crypto module is not loaded\n */\nexport function getNodeCrypto(): typeof import(\"node:crypto\") {\n\tif (!nodeCrypto) {\n\t\tthrow new Error(\n\t\t\t\"Node crypto module not loaded. Ensure importNodeDependencies() has been called.\",\n\t\t);\n\t}\n\treturn nodeCrypto;\n}\n\n/**\n * Gets the Node.js fs module.\n * @throws Error if fs module is not loaded\n */\nexport function getNodeFsSync(): typeof import(\"node:fs\") {\n\tif (!nodeFsSync) {\n\t\tthrow new Error(\n\t\t\t\"Node fs module not loaded. Ensure importNodeDependencies() has been called.\",\n\t\t);\n\t}\n\treturn nodeFsSync;\n}\n\n/**\n * Gets the Node.js fs/promises module.\n * @throws Error if fs/promises module is not loaded\n */\nexport function getNodeFs(): typeof import(\"node:fs/promises\") {\n\tif (!nodeFs) {\n\t\tthrow new Error(\n\t\t\t\"Node fs/promises module not loaded. Ensure importNodeDependencies() has been called.\",\n\t\t);\n\t}\n\treturn nodeFs;\n}\n\n/**\n * Gets the Node.js path module.\n * @throws Error if path module is not loaded\n */\nexport function getNodePath(): typeof import(\"node:path\") {\n\tif (!nodePath) {\n\t\tthrow new Error(\n\t\t\t\"Node path module not loaded. Ensure importNodeDependencies() has been called.\",\n\t\t);\n\t}\n\treturn nodePath;\n}\n\n/**\n * Gets the Node.js os module.\n * @throws Error if os module is not loaded\n */\nexport function getNodeOs(): typeof import(\"node:os\") {\n\tif (!nodeOs) {\n\t\tthrow new Error(\n\t\t\t\"Node os module not loaded. Ensure importNodeDependencies() has been called.\",\n\t\t);\n\t}\n\treturn nodeOs;\n}\n\n/**\n * Gets the Node.js child_process module.\n * @throws Error if child_process module is not loaded\n */\nexport function getNodeChildProcess(): typeof import(\"node:child_process\") {\n\tif (!nodeChildProcess) {\n\t\tthrow new Error(\n\t\t\t\"Node child_process module not loaded. Ensure importNodeDependencies() has been called.\",\n\t\t);\n\t}\n\treturn nodeChildProcess;\n}\n\n/**\n * Gets the Node.js stream/promises module.\n * @throws Error if stream/promises module is not loaded\n */\nexport function getNodeStream(): typeof import(\"node:stream/promises\") {\n\tif (!nodeStream) {\n\t\tthrow new Error(\n\t\t\t\"Node stream/promises module not loaded. Ensure importNodeDependencies() has been called.\",\n\t\t);\n\t}\n\treturn nodeStream;\n}\n","import type { AnyClient } from \"@/client/client\";\nimport type {\n\tActorDriver,\n\tAnyActorInstance,\n\tManagerDriver,\n} from \"@/driver-helpers/mod\";\nimport type { RegistryConfig, RunConfig } from \"@/mod\";\nimport type { FileSystemGlobalState } from \"./global-state\";\n\nexport type ActorDriverContext = Record<never, never>;\n\n/**\n * File System implementation of the Actor Driver\n */\nexport class FileSystemActorDriver implements ActorDriver {\n\t#registryConfig: RegistryConfig;\n\t#runConfig: RunConfig;\n\t#managerDriver: ManagerDriver;\n\t#inlineClient: AnyClient;\n\t#state: FileSystemGlobalState;\n\n\tconstructor(\n\t\tregistryConfig: RegistryConfig,\n\t\trunConfig: RunConfig,\n\t\tmanagerDriver: ManagerDriver,\n\t\tinlineClient: AnyClient,\n\t\tstate: FileSystemGlobalState,\n\t) {\n\t\tthis.#registryConfig = registryConfig;\n\t\tthis.#runConfig = runConfig;\n\t\tthis.#managerDriver = managerDriver;\n\t\tthis.#inlineClient = inlineClient;\n\t\tthis.#state = state;\n\t}\n\n\tasync loadActor(actorId: string): Promise<AnyActorInstance> {\n\t\treturn this.#state.startActor(\n\t\t\tthis.#registryConfig,\n\t\t\tthis.#runConfig,\n\t\t\tthis.#inlineClient,\n\t\t\tthis,\n\t\t\tactorId,\n\t\t);\n\t}\n\n\t/**\n\t * Get the current storage directory path\n\t */\n\tget storagePath(): string {\n\t\treturn this.#state.storagePath;\n\t}\n\n\tgetContext(_actorId: string): ActorDriverContext {\n\t\treturn {};\n\t}\n\n\tasync kvBatchPut(\n\t\tactorId: string,\n\t\tentries: [Uint8Array, Uint8Array][],\n\t): Promise<void> {\n\t\tawait this.#state.kvBatchPut(actorId, entries);\n\t}\n\n\tasync kvBatchGet(\n\t\tactorId: string,\n\t\tkeys: Uint8Array[],\n\t): Promise<(Uint8Array | null)[]> {\n\t\treturn await this.#state.kvBatchGet(actorId, keys);\n\t}\n\n\tasync kvBatchDelete(actorId: string, keys: Uint8Array[]): Promise<void> {\n\t\tawait this.#state.kvBatchDelete(actorId, keys);\n\t}\n\n\tasync kvListPrefix(\n\t\tactorId: string,\n\t\tprefix: Uint8Array,\n\t): Promise<[Uint8Array, Uint8Array][]> {\n\t\treturn await this.#state.kvListPrefix(actorId, prefix);\n\t}\n\n\tasync setAlarm(actor: AnyActorInstance, timestamp: number): Promise<void> {\n\t\tawait this.#state.setActorAlarm(actor.id, timestamp);\n\t}\n\n\tgetDatabase(actorId: string): Promise<unknown | undefined> {\n\t\treturn this.#state.createDatabase(actorId);\n\t}\n\n\tstartSleep(actorId: string): void {\n\t\t// Spawns the sleepActor promise\n\t\tthis.#state.sleepActor(actorId);\n\t}\n\n\tasync startDestroy(actorId: string): Promise<void> {\n\t\tawait this.#state.destroyActor(actorId);\n\t}\n}\n","import invariant from \"invariant\";\nimport { lookupInRegistry } from \"@/actor/definition\";\nimport { ActorDuplicateKey } from \"@/actor/errors\";\nimport type { AnyActorInstance } from \"@/actor/instance/mod\";\nimport type { ActorKey } from \"@/actor/mod\";\nimport { generateRandomString } from \"@/actor/utils\";\nimport type { AnyClient } from \"@/client/client\";\nimport { type ActorDriver, getInitialActorKvState } from \"@/driver-helpers/mod\";\nimport type { RegistryConfig } from \"@/registry/config\";\nimport type { RunnerConfig } from \"@/registry/run-config\";\nimport type * as schema from \"@/schemas/file-system-driver/mod\";\nimport {\n\tACTOR_ALARM_VERSIONED,\n\tACTOR_STATE_VERSIONED,\n\tCURRENT_VERSION as FILE_SYSTEM_DRIVER_CURRENT_VERSION,\n} from \"@/schemas/file-system-driver/versioned\";\nimport {\n\tarrayBuffersEqual,\n\tbufferToArrayBuffer,\n\ttype LongTimeoutHandle,\n\tpromiseWithResolvers,\n\tsetLongTimeout,\n\tstringifyError,\n} from \"@/utils\";\nimport {\n\tgetNodeCrypto,\n\tgetNodeFs,\n\tgetNodeFsSync,\n\tgetNodePath,\n} from \"@/utils/node\";\nimport { logger } from \"./log\";\nimport {\n\tensureDirectoryExists,\n\tensureDirectoryExistsSync,\n\tgetStoragePath,\n} from \"./utils\";\n\n// Actor handler to track running instances\n\nenum ActorLifecycleState {\n\tNONEXISTENT, // Entry exists but actor not yet created\n\tAWAKE, // Actor is running normally\n\tSTARTING_SLEEP, // Actor is being put to sleep\n\tSTARTING_DESTROY, // Actor is being destroyed\n\tDESTROYED, // Actor was destroyed, should not be recreated\n}\n\ninterface ActorEntry {\n\tid: string;\n\n\tstate?: schema.ActorState;\n\n\t/** Promise for loading the actor state. */\n\tloadPromise?: Promise<ActorEntry>;\n\n\tactor?: AnyActorInstance;\n\t/** Promise for starting the actor. */\n\tstartPromise?: ReturnType<typeof promiseWithResolvers<void>>;\n\n\talarmTimeout?: LongTimeoutHandle;\n\t/** The timestamp currently scheduled for this actor's alarm (ms since epoch). */\n\talarmTimestamp?: number;\n\n\t/** Resolver for pending write operations that need to be notified when any write completes */\n\tpendingWriteResolver?: PromiseWithResolvers<void>;\n\n\tlifecycleState: ActorLifecycleState;\n\n\t// TODO: This might make sense to move in to actorstate, but we have a\n\t// single reader/writer so it's not an issue\n\t/** Generation of this actor when creating/destroying. */\n\tgeneration: string;\n}\n\n/**\n * Global state for the file system driver\n */\nexport class FileSystemGlobalState {\n\t#storagePath: string;\n\t#stateDir: string;\n\t#dbsDir: string;\n\t#alarmsDir: string;\n\n\t#persist: boolean;\n\n\t// IMPORTANT: Never delete from this map. Doing so will result in race\n\t// conditions since the actor generation will cease to be tracked\n\t// correctly. Always increment generation if a new actor is created.\n\t#actors = new Map<string, ActorEntry>();\n\n\t#actorCountOnStartup: number = 0;\n\n\t#runnerParams?: {\n\t\tregistryConfig: RegistryConfig;\n\t\trunConfig: RunnerConfig;\n\t\tinlineClient: AnyClient;\n\t\tactorDriver: ActorDriver;\n\t};\n\n\tget persist(): boolean {\n\t\treturn this.#persist;\n\t}\n\n\tget storagePath() {\n\t\treturn this.#storagePath;\n\t}\n\n\tget actorCountOnStartup() {\n\t\treturn this.#actorCountOnStartup;\n\t}\n\n\tconstructor(persist: boolean = true, customPath?: string) {\n\t\tthis.#persist = persist;\n\t\tthis.#storagePath = persist ? (customPath ?? getStoragePath()) : \"/tmp\";\n\t\tconst path = getNodePath();\n\t\tthis.#stateDir = path.join(this.#storagePath, \"state\");\n\t\tthis.#dbsDir = path.join(this.#storagePath, \"databases\");\n\t\tthis.#alarmsDir = path.join(this.#storagePath, \"alarms\");\n\n\t\tif (this.#persist) {\n\t\t\t// Ensure storage directories exist synchronously during initialization\n\t\t\tensureDirectoryExistsSync(this.#stateDir);\n\t\t\tensureDirectoryExistsSync(this.#dbsDir);\n\t\t\tensureDirectoryExistsSync(this.#alarmsDir);\n\n\t\t\ttry {\n\t\t\t\tconst fsSync = getNodeFsSync();\n\t\t\t\tconst actorIds = fsSync.readdirSync(this.#stateDir);\n\t\t\t\tthis.#actorCountOnStartup = actorIds.length;\n\t\t\t} catch (error) {\n\t\t\t\tlogger().error({ msg: \"failed to count actors\", error });\n\t\t\t}\n\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"file system driver ready\",\n\t\t\t\tdir: this.#storagePath,\n\t\t\t\tactorCount: this.#actorCountOnStartup,\n\t\t\t});\n\n\t\t\t// Cleanup stale temp files on startup\n\t\t\ttry {\n\t\t\t\tthis.#cleanupTempFilesSync();\n\t\t\t} catch (err) {\n\t\t\t\tlogger().error({\n\t\t\t\t\tmsg: \"failed to cleanup temp files\",\n\t\t\t\t\terror: err,\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tlogger().debug({ msg: \"memory driver ready\" });\n\t\t}\n\t}\n\n\tgetActorStatePath(actorId: string): string {\n\t\treturn getNodePath().join(this.#stateDir, actorId);\n\t}\n\n\tgetActorDbPath(actorId: string): string {\n\t\treturn getNodePath().join(this.#dbsDir, `${actorId}.db`);\n\t}\n\n\tgetActorAlarmPath(actorId: string): string {\n\t\treturn getNodePath().join(this.#alarmsDir, actorId);\n\t}\n\n\tasync *getActorsIterator(params: {\n\t\tcursor?: string;\n\t}): AsyncGenerator<schema.ActorState> {\n\t\tlet actorIds = Array.from(this.#actors.keys()).sort();\n\n\t\t// Check if state directory exists first\n\t\tconst fsSync = getNodeFsSync();\n\t\tif (fsSync.existsSync(this.#stateDir)) {\n\t\t\tactorIds = fsSync\n\t\t\t\t.readdirSync(this.#stateDir)\n\t\t\t\t.filter((id) => !id.includes(\".tmp\"))\n\t\t\t\t.sort();\n\t\t}\n\n\t\tconst startIndex = params.cursor\n\t\t\t? actorIds.indexOf(params.cursor) + 1\n\t\t\t: 0;\n\n\t\tfor (let i = startIndex; i < actorIds.length; i++) {\n\t\t\tconst actorId = actorIds[i];\n\t\t\tif (!actorId) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst state = await this.loadActorStateOrError(actorId);\n\t\t\t\tyield state;\n\t\t\t} catch (error) {\n\t\t\t\tlogger().error({\n\t\t\t\t\tmsg: \"failed to load actor state\",\n\t\t\t\t\tactorId,\n\t\t\t\t\terror,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Ensures an entry exists for this actor.\n\t *\n\t * Used for #createActor and #loadActor.\n\t */\n\t#upsertEntry(actorId: string): ActorEntry {\n\t\tlet entry = this.#actors.get(actorId);\n\t\tif (entry) {\n\t\t\treturn entry;\n\t\t}\n\n\t\tentry = {\n\t\t\tid: actorId,\n\t\t\tlifecycleState: ActorLifecycleState.NONEXISTENT,\n\t\t\tgeneration: crypto.randomUUID(),\n\t\t};\n\t\tthis.#actors.set(actorId, entry);\n\t\treturn entry;\n\t}\n\n\t/**\n\t * Creates a new actor and writes to file system.\n\t */\n\tasync createActor(\n\t\tactorId: string,\n\t\tname: string,\n\t\tkey: ActorKey,\n\t\tinput: unknown | undefined,\n\t): Promise<ActorEntry> {\n\t\t// TODO: Does not check if actor already exists on fs\n\n\t\tconst entry = this.#upsertEntry(actorId);\n\n\t\t// Check if actor already exists (has state or is being stopped)\n\t\tif (entry.state) {\n\t\t\tthrow new ActorDuplicateKey(name, key);\n\t\t}\n\t\tif (this.isActorStopping(actorId)) {\n\t\t\tthrow new Error(`Actor ${actorId} is stopping`);\n\t\t}\n\n\t\t// If actor was destroyed, reset to NONEXISTENT and increment generation\n\t\tif (entry.lifecycleState === ActorLifecycleState.DESTROYED) {\n\t\t\tentry.lifecycleState = ActorLifecycleState.NONEXISTENT;\n\t\t\tentry.generation = crypto.randomUUID();\n\t\t}\n\n\t\t// Initialize storage\n\t\tconst kvStorage: schema.ActorKvEntry[] = [];\n\t\tconst initialKvState = getInitialActorKvState(input);\n\t\tfor (const [key, value] of initialKvState) {\n\t\t\tkvStorage.push({\n\t\t\t\tkey: bufferToArrayBuffer(key),\n\t\t\t\tvalue: bufferToArrayBuffer(value),\n\t\t\t});\n\t\t}\n\n\t\t// Initialize metadata\n\t\tentry.state = {\n\t\t\tactorId,\n\t\t\tname,\n\t\t\tkey,\n\t\t\tcreatedAt: BigInt(Date.now()),\n\t\t\tkvStorage,\n\t\t\tstartTs: null,\n\t\t\tconnectableTs: null,\n\t\t\tsleepTs: null,\n\t\t\tdestroyTs: null,\n\t\t};\n\t\tentry.lifecycleState = ActorLifecycleState.AWAKE;\n\n\t\tawait this.writeActor(actorId, entry.generation, entry.state);\n\n\t\treturn entry;\n\t}\n\n\t/**\n\t * Loads the actor from disk or returns the existing actor entry. This will return an entry even if the actor does not actually exist.\n\t */\n\tasync loadActor(actorId: string): Promise<ActorEntry> {\n\t\tconst entry = this.#upsertEntry(actorId);\n\n\t\t// Check if destroyed - don't load from disk\n\t\tif (entry.lifecycleState === ActorLifecycleState.DESTROYED) {\n\t\t\treturn entry;\n\t\t}\n\n\t\t// Check if already loaded\n\t\tif (entry.state) {\n\t\t\treturn entry;\n\t\t}\n\n\t\t// If not persisted, then don't load from FS\n\t\tif (!this.#persist) {\n\t\t\treturn entry;\n\t\t}\n\n\t\t// If state is currently being loaded, wait for it\n\t\tif (entry.loadPromise) {\n\t\t\tawait entry.loadPromise;\n\t\t\treturn entry;\n\t\t}\n\n\t\t// Start loading state\n\t\tentry.loadPromise = this.loadActorState(entry);\n\t\treturn entry.loadPromise;\n\t}\n\n\tprivate async loadActorState(entry: ActorEntry) {\n\t\tconst stateFilePath = this.getActorStatePath(entry.id);\n\n\t\t// Read & parse file\n\t\ttry {\n\t\t\tconst fs = getNodeFs();\n\t\t\tconst stateData = await fs.readFile(stateFilePath);\n\n\t\t\t// Cache the loaded state in handler\n\t\t\tentry.state = ACTOR_STATE_VERSIONED.deserializeWithEmbeddedVersion(\n\t\t\t\tnew Uint8Array(stateData),\n\t\t\t);\n\n\t\t\treturn entry;\n\t\t} catch (innerError: any) {\n\t\t\t// File does not exist, meaning the actor does not exist\n\t\t\tif (innerError.code === \"ENOENT\") {\n\t\t\t\tentry.loadPromise = undefined;\n\t\t\t\treturn entry;\n\t\t\t}\n\n\t\t\t// For other errors, throw\n\t\t\tconst error = new Error(\n\t\t\t\t`Failed to load actor state: ${innerError}`,\n\t\t\t);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync loadOrCreateActor(\n\t\tactorId: string,\n\t\tname: string,\n\t\tkey: ActorKey,\n\t\tinput: unknown | undefined,\n\t): Promise<ActorEntry> {\n\t\t// Attempt to load actor\n\t\tconst entry = await this.loadActor(actorId);\n\n\t\t// If no state for this actor, then create & write state\n\t\tif (!entry.state) {\n\t\t\tif (this.isActorStopping(actorId)) {\n\t\t\t\tthrow new Error(`Actor ${actorId} stopping`);\n\t\t\t}\n\n\t\t\t// If actor was destroyed, reset to NONEXISTENT and increment generation\n\t\t\tif (entry.lifecycleState === ActorLifecycleState.DESTROYED) {\n\t\t\t\tentry.lifecycleState = ActorLifecycleState.NONEXISTENT;\n\t\t\t\tentry.generation = crypto.randomUUID();\n\t\t\t}\n\n\t\t\t// Initialize kvStorage with the initial persist data\n\t\t\tconst kvStorage: schema.ActorKvEntry[] = [];\n\t\t\tconst initialKvState = getInitialActorKvState(input);\n\t\t\tfor (const [key, value] of initialKvState) {\n\t\t\t\tkvStorage.push({\n\t\t\t\t\tkey: bufferToArrayBuffer(key),\n\t\t\t\t\tvalue: bufferToArrayBuffer(value),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tentry.state = {\n\t\t\t\tactorId,\n\t\t\t\tname,\n\t\t\t\tkey: key as readonly string[],\n\t\t\t\tcreatedAt: BigInt(Date.now()),\n\t\t\t\tkvStorage,\n\t\t\t\tstartTs: null,\n\t\t\t\tconnectableTs: null,\n\t\t\t\tsleepTs: null,\n\t\t\t\tdestroyTs: null,\n\t\t\t};\n\t\t\tawait this.writeActor(actorId, entry.generation, entry.state);\n\t\t}\n\t\treturn entry;\n\t}\n\n\tasync sleepActor(actorId: string) {\n\t\tinvariant(\n\t\t\tthis.#persist,\n\t\t\t\"cannot sleep actor with memory driver, must use file system driver\",\n\t\t);\n\n\t\t// Get the actor. We upsert it even though we're about to destroy it so we have a lock on flagging `destroying` as true.\n\t\tconst actor = this.#upsertEntry(actorId);\n\t\tinvariant(actor, `tried to sleep ${actorId}, does not exist`);\n\n\t\t// Check if already destroying\n\t\tif (this.isActorStopping(actorId)) {\n\t\t\treturn;\n\t\t}\n\t\tactor.lifecycleState = ActorLifecycleState.STARTING_SLEEP;\n\n\t\t// Wait for actor to fully start before stopping it to avoid race conditions\n\t\tif (actor.loadPromise) await actor.loadPromise.catch();\n\t\tif (actor.startPromise?.promise)\n\t\t\tawait actor.startPromise.promise.catch();\n\n\t\t// Update state with sleep timestamp\n\t\tif (actor.state) {\n\t\t\tactor.state = {\n\t\t\t\t...actor.state,\n\t\t\t\tsleepTs: BigInt(Date.now()),\n\t\t\t};\n\t\t\tawait this.writeActor(actorId, actor.generation, actor.state);\n\t\t}\n\n\t\t// Stop actor\n\t\tinvariant(actor.actor, \"actor should be loaded\");\n\t\tawait actor.actor.onStop(\"sleep\");\n\n\t\t// Remove from map after stop is complete\n\t\tthis.#actors.delete(actorId);\n\t}\n\n\tasync destroyActor(actorId: string) {\n\t\t// Get the actor. We upsert it even though we're about to destroy it so we have a lock on flagging `destroying` as true.\n\t\tconst actor = this.#upsertEntry(actorId);\n\n\t\t// If actor is loaded, stop it first\n\t\t// Check if already destroying\n\t\tif (this.isActorStopping(actorId)) {\n\t\t\treturn;\n\t\t}\n\t\tactor.lifecycleState = ActorLifecycleState.STARTING_DESTROY;\n\n\t\t// Wait for actor to fully start before stopping it to avoid race conditions\n\t\tif (actor.loadPromise) await actor.loadPromise.catch();\n\t\tif (actor.startPromise?.promise)\n\t\t\tawait actor.startPromise.promise.catch();\n\n\t\t// Update state with destroy timestamp\n\t\tif (actor.state) {\n\t\t\tactor.state = {\n\t\t\t\t...actor.state,\n\t\t\t\tdestroyTs: BigInt(Date.now()),\n\t\t\t};\n\t\t\tawait this.writeActor(actorId, actor.generation, actor.state);\n\t\t}\n\n\t\t// Stop actor if it's running\n\t\tif (actor.actor) {\n\t\t\tawait actor.actor.onStop(\"destroy\");\n\t\t}\n\n\t\t// Clear alarm timeout if exists\n\t\tif (actor.alarmTimeout) {\n\t\t\tactor.alarmTimeout.abort();\n\t\t}\n\n\t\t// Delete persisted files if using file system driver\n\t\tif (this.#persist) {\n\t\t\tconst fs = getNodeFs();\n\n\t\t\t// Delete all actor files in parallel\n\t\t\tawait Promise.all([\n\t\t\t\t// Delete actor state file\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait fs.unlink(this.getActorStatePath(actorId));\n\t\t\t\t\t} catch (err: any) {\n\t\t\t\t\t\tif (err?.code !== \"ENOENT\") {\n\t\t\t\t\t\t\tlogger().error({\n\t\t\t\t\t\t\t\tmsg: \"failed to delete actor state file\",\n\t\t\t\t\t\t\t\tactorId,\n\t\t\t\t\t\t\t\terror: stringifyError(err),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t})(),\n\t\t\t\t// Delete actor database file\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait fs.unlink(this.getActorDbPath(actorId));\n\t\t\t\t\t} catch (err: any) {\n\t\t\t\t\t\tif (err?.code !== \"ENOENT\") {\n\t\t\t\t\t\t\tlogger().error({\n\t\t\t\t\t\t\t\tmsg: \"failed to delete actor database file\",\n\t\t\t\t\t\t\t\tactorId,\n\t\t\t\t\t\t\t\terror: stringifyError(err),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t})(),\n\t\t\t\t// Delete actor alarm file\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait fs.unlink(this.getActorAlarmPath(actorId));\n\t\t\t\t\t} catch (err: any) {\n\t\t\t\t\t\tif (err?.code !== \"ENOENT\") {\n\t\t\t\t\t\t\tlogger().error({\n\t\t\t\t\t\t\t\tmsg: \"failed to delete actor alarm file\",\n\t\t\t\t\t\t\t\tactorId,\n\t\t\t\t\t\t\t\terror: stringifyError(err),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t})(),\n\t\t\t]);\n\t\t}\n\n\t\t// Reset the entry\n\t\t//\n\t\t// Do not remove entry in order to avoid race condition with\n\t\t// destroying. Next actor creation will increment the generation.\n\t\tactor.state = undefined;\n\t\tactor.loadPromise = undefined;\n\t\tactor.actor = undefined;\n\t\tactor.startPromise = undefined;\n\t\tactor.alarmTimeout = undefined;\n\t\tactor.alarmTimeout = undefined;\n\t\tactor.pendingWriteResolver = undefined;\n\t\tactor.lifecycleState = ActorLifecycleState.DESTROYED;\n\t}\n\n\t/**\n\t * Save actor state to disk.\n\t */\n\tasync writeActor(\n\t\tactorId: string,\n\t\tgeneration: string,\n\t\tstate: schema.ActorState,\n\t): Promise<void> {\n\t\tif (!this.#persist) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst entry = this.#actors.get(actorId);\n\t\tinvariant(entry, \"actor entry does not exist\");\n\n\t\tawait this.#performWrite(actorId, generation, state);\n\t}\n\n\tisGenerationCurrentAndNotDestroyed(\n\t\tactorId: string,\n\t\tgeneration: string,\n\t): boolean {\n\t\tconst entry = this.#upsertEntry(actorId);\n\t\tif (!entry) return false;\n\t\treturn (\n\t\t\tentry.generation === generation &&\n\t\t\tentry.lifecycleState !== ActorLifecycleState.STARTING_DESTROY\n\t\t);\n\t}\n\n\tisActorStopping(actorId: string) {\n\t\tconst entry = this.#upsertEntry(actorId);\n\t\tif (!entry) return false;\n\t\treturn (\n\t\t\tentry.lifecycleState === ActorLifecycleState.STARTING_SLEEP ||\n\t\t\tentry.lifecycleState === ActorLifecycleState.STARTING_DESTROY\n\t\t);\n\t}\n\n\tasync setActorAlarm(actorId: string, timestamp: number) {\n\t\tconst entry = this.#actors.get(actorId);\n\t\tinvariant(entry, \"actor entry does not exist\");\n\n\t\t// Track generation of the actor when the write started to detect\n\t\t// destroy/create race condition\n\t\tconst writeGeneration = entry.generation;\n\t\tif (this.isActorStopping(actorId)) {\n\t\t\tlogger().info(\"skipping set alarm since actor stopping\");\n\t\t\treturn;\n\t\t}\n\n\t\t// Persist alarm to disk\n\t\tif (this.#persist) {\n\t\t\tconst alarmPath = this.getActorAlarmPath(actorId);\n\t\t\tconst crypto = getNodeCrypto();\n\t\t\tconst tempPath = `${alarmPath}.tmp.${crypto.randomUUID()}`;\n\t\t\ttry {\n\t\t\t\tconst path = getNodePath();\n\t\t\t\tawait ensureDirectoryExists(path.dirname(alarmPath));\n\t\t\t\tconst alarmData: schema.ActorAlarm = {\n\t\t\t\t\tactorId,\n\t\t\t\t\ttimestamp: BigInt(timestamp),\n\t\t\t\t};\n\t\t\t\tconst data =\n\t\t\t\t\tACTOR_ALARM_VERSIONED.serializeWithEmbeddedVersion(\n\t\t\t\t\t\talarmData,\n\t\t\t\t\t\tFILE_SYSTEM_DRIVER_CURRENT_VERSION,\n\t\t\t\t\t);\n\t\t\t\tconst fs = getNodeFs();\n\t\t\t\tawait fs.writeFile(tempPath, data);\n\n\t\t\t\tif (\n\t\t\t\t\t!this.isGenerationCurrentAndNotDestroyed(\n\t\t\t\t\t\tactorId,\n\t\t\t\t\t\twriteGeneration,\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tlogger().debug(\n\t\t\t\t\t\t\"skipping writing alarm since actor destroying or new generation\",\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tawait fs.rename(tempPath, alarmPath);\n\t\t\t} catch (error) {\n\t\t\t\ttry {\n\t\t\t\t\tconst fs = getNodeFs();\n\t\t\t\t\tawait fs.unlink(tempPath);\n\t\t\t\t} catch {}\n\t\t\t\tlogger().error({\n\t\t\t\t\tmsg: \"failed to write alarm\",\n\t\t\t\t\tactorId,\n\t\t\t\t\terror,\n\t\t\t\t});\n\t\t\t\tthrow new Error(`Failed to write alarm: ${error}`);\n\t\t\t}\n\t\t}\n\n\t\t// Schedule timeout\n\t\tthis.#scheduleAlarmTimeout(actorId, timestamp);\n\t}\n\n\t/**\n\t * Perform the actual write operation with atomic writes\n\t */\n\tasync #performWrite(\n\t\tactorId: string,\n\t\tgeneration: string,\n\t\tstate: schema.ActorState,\n\t): Promise<void> {\n\t\tconst dataPath = this.getActorStatePath(actorId);\n\t\t// Generate unique temp filename to prevent any race conditions\n\t\tconst crypto = getNodeCrypto();\n\t\tconst tempPath = `${dataPath}.tmp.${crypto.randomUUID()}`;\n\n\t\ttry {\n\t\t\t// Create directory if needed\n\t\t\tconst path = getNodePath();\n\t\t\tawait ensureDirectoryExists(path.dirname(dataPath));\n\n\t\t\t// Convert to BARE types for serialization\n\t\t\tconst bareState: schema.ActorState = {\n\t\t\t\tactorId: state.actorId,\n\t\t\t\tname: state.name,\n\t\t\t\tkey: state.key,\n\t\t\t\tcreatedAt: state.createdAt,\n\t\t\t\tkvStorage: state.kvStorage,\n\t\t\t\tstartTs: state.startTs,\n\t\t\t\tconnectableTs: state.connectableTs,\n\t\t\t\tsleepTs: state.sleepTs,\n\t\t\t\tdestroyTs: state.destroyTs,\n\t\t\t};\n\n\t\t\t// Perform atomic write\n\t\t\tconst serializedState =\n\t\t\t\tACTOR_STATE_VERSIONED.serializeWithEmbeddedVersion(\n\t\t\t\t\tbareState,\n\t\t\t\t\tFILE_SYSTEM_DRIVER_CURRENT_VERSION,\n\t\t\t\t);\n\t\t\tconst fs = getNodeFs();\n\t\t\tawait fs.writeFile(tempPath, serializedState);\n\n\t\t\tif (!this.isGenerationCurrentAndNotDestroyed(actorId, generation)) {\n\t\t\t\tlogger().debug(\n\t\t\t\t\t\"skipping writing alarm since actor destroying or new generation\",\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tawait fs.rename(tempPath, dataPath);\n\t\t} catch (error) {\n\t\t\t// Cleanup temp file on error\n\t\t\ttry {\n\t\t\t\tconst fs = getNodeFs();\n\t\t\t\tawait fs.unlink(tempPath);\n\t\t\t} catch {\n\t\t\t\t// Ignore cleanup errors\n\t\t\t}\n\t\t\tlogger().error({\n\t\t\t\tmsg: \"failed to save actor state\",\n\t\t\t\tactorId,\n\t\t\t\terror,\n\t\t\t});\n\t\t\tthrow new Error(`Failed to save actor state: ${error}`);\n\t\t}\n\t}\n\n\t/**\n\t * Call this method after the actor driver has been initiated.\n\t *\n\t * This will trigger all initial alarms from the file system.\n\t *\n\t * This needs to be sync since DriverConfig.actor is sync\n\t */\n\tonRunnerStart(\n\t\tregistryConfig: RegistryConfig,\n\t\trunConfig: RunnerConfig,\n\t\tinlineClient: AnyClient,\n\t\tactorDriver: ActorDriver,\n\t) {\n\t\tif (this.#runnerParams) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Save runner params for future use\n\t\tthis.#runnerParams = {\n\t\t\tregistryConfig,\n\t\t\trunConfig,\n\t\t\tinlineClient,\n\t\t\tactorDriver,\n\t\t};\n\n\t\t// Load alarms from disk and schedule timeouts\n\t\ttry {\n\t\t\tthis.#loadAlarmsSync();\n\t\t} catch (err) {\n\t\t\tlogger().error({\n\t\t\t\tmsg: \"failed to load alarms on startup\",\n\t\t\t\terror: err,\n\t\t\t});\n\t\t}\n\t}\n\n\tasync startActor(\n\t\tregistryConfig: RegistryConfig,\n\t\trunConfig: RunnerConfig,\n\t\tinlineClient: AnyClient,\n\t\tactorDriver: ActorDriver,\n\t\tactorId: string,\n\t): Promise<AnyActorInstance> {\n\t\t// Get the actor metadata\n\t\tconst entry = await this.loadActor(actorId);\n\t\tif (!entry.state) {\n\t\t\tthrow new Error(\n\t\t\t\t`Actor does not exist and cannot be started: \"${actorId}\"`,\n\t\t\t);\n\t\t}\n\n\t\t// Actor already starting\n\t\tif (entry.startPromise) {\n\t\t\tawait entry.startPromise.promise;\n\t\t\tinvariant(entry.actor, \"actor should have loaded\");\n\t\t\treturn entry.actor;\n\t\t}\n\n\t\t// Actor already loaded\n\t\tif (entry.actor) {\n\t\t\treturn entry.actor;\n\t\t}\n\n\t\t// Create start promise\n\t\tentry.startPromise = promiseWithResolvers();\n\n\t\ttry {\n\t\t\t// Create actor\n\t\t\tconst definition = lookupInRegistry(\n\t\t\t\tregistryConfig,\n\t\t\t\tentry.state.name,\n\t\t\t);\n\t\t\tentry.actor = definition.instantiate();\n\n\t\t\t// Start actor\n\t\t\tawait entry.actor.start(\n\t\t\t\tactorDriver,\n\t\t\t\tinlineClient,\n\t\t\t\tactorId,\n\t\t\t\tentry.state.name,\n\t\t\t\tentry.state.key as string[],\n\t\t\t\t\"unknown\",\n\t\t\t);\n\n\t\t\t// Update state with start timestamp\n\t\t\t// NOTE: connectableTs is always in sync with startTs since actors become connectable immediately after starting\n\t\t\tconst now = BigInt(Date.now());\n\t\t\tentry.state = {\n\t\t\t\t...entry.state,\n\t\t\t\tstartTs: now,\n\t\t\t\tconnectableTs: now,\n\t\t\t};\n\t\t\tawait this.writeActor(actorId, entry.generation, entry.state);\n\n\t\t\t// Finish\n\t\t\tentry.startPromise.resolve();\n\t\t\tentry.startPromise = undefined;\n\n\t\t\treturn entry.actor;\n\t\t} catch (innerError) {\n\t\t\tconst error = new Error(\n\t\t\t\t`Failed to start actor ${actorId}: ${innerError}`,\n\t\t\t\t{ cause: innerError },\n\t\t\t);\n\t\t\tentry.startPromise?.reject(error);\n\t\t\tentry.startPromise = undefined;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync loadActorStateOrError(actorId: string): Promise<schema.ActorState> {\n\t\tconst state = (await this.loadActor(actorId)).state;\n\t\tif (!state) throw new Error(`Actor does not exist: ${actorId}`);\n\t\treturn state;\n\t}\n\n\tgetActorOrError(actorId: string): ActorEntry {\n\t\tconst entry = this.#actors.get(actorId);\n\t\tif (!entry) throw new Error(`No entry for actor: ${actorId}`);\n\t\treturn entry;\n\t}\n\n\tasync createDatabase(actorId: string): Promise<string | undefined> {\n\t\treturn this.getActorDbPath(actorId);\n\t}\n\n\t/**\n\t * Load all persisted alarms from disk and schedule their timers.\n\t */\n\t#loadAlarmsSync(): void {\n\t\ttry {\n\t\t\tconst fsSync = getNodeFsSync();\n\t\t\tconst files = fsSync.existsSync(this.#alarmsDir)\n\t\t\t\t? fsSync.readdirSync(this.#alarmsDir)\n\t\t\t\t: [];\n\t\t\tfor (const file of files) {\n\t\t\t\t// Skip temp files\n\t\t\t\tif (file.includes(\".tmp.\")) continue;\n\t\t\t\tconst path = getNodePath();\n\t\t\t\tconst fullPath = path.join(this.#alarmsDir, file);\n\t\t\t\ttry {\n\t\t\t\t\tconst buf = fsSync.readFileSync(fullPath);\n\t\t\t\t\tconst alarmData =\n\t\t\t\t\t\tACTOR_ALARM_VERSIONED.deserializeWithEmbeddedVersion(\n\t\t\t\t\t\t\tnew Uint8Array(buf),\n\t\t\t\t\t\t);\n\t\t\t\t\tconst timestamp = Number(alarmData.timestamp);\n\t\t\t\t\tif (Number.isFinite(timestamp)) {\n\t\t\t\t\t\tthis.#scheduleAlarmTimeout(\n\t\t\t\t\t\t\talarmData.actorId,\n\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger().debug({\n\t\t\t\t\t\t\tmsg: \"invalid alarm file contents\",\n\t\t\t\t\t\t\tfile,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tlogger().error({\n\t\t\t\t\t\tmsg: \"failed to read alarm file\",\n\t\t\t\t\t\tfile,\n\t\t\t\t\t\terror: stringifyError(err),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tlogger().error({\n\t\t\t\tmsg: \"failed to list alarms directory\",\n\t\t\t\terror: err,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Schedule an alarm timer for an actor without writing to disk.\n\t */\n\t#scheduleAlarmTimeout(actorId: string, timestamp: number) {\n\t\tconst entry = this.#upsertEntry(actorId);\n\n\t\t// If there's already an earlier alarm scheduled, do not override it.\n\t\tif (\n\t\t\tentry.alarmTimestamp !== undefined &&\n\t\t\ttimestamp >= entry.alarmTimestamp\n\t\t) {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"skipping alarm schedule (later than existing)\",\n\t\t\t\tactorId,\n\t\t\t\ttimestamp,\n\t\t\t\tcurrent: entry.alarmTimestamp,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tlogger().debug({ msg: \"scheduling alarm\", actorId, timestamp });\n\n\t\t// Cancel existing timeout and update the current scheduled timestamp\n\t\tentry.alarmTimeout?.abort();\n\t\tentry.alarmTimestamp = timestamp;\n\n\t\tconst delay = Math.max(0, timestamp - Date.now());\n\t\tentry.alarmTimeout = setLongTimeout(async () => {\n\t\t\t// Clear currently scheduled timestamp as this alarm is firing now\n\t\t\tentry.alarmTimestamp = undefined;\n\t\t\t// On trigger: remove persisted alarm file\n\t\t\tif (this.#persist) {\n\t\t\t\ttry {\n\t\t\t\t\tconst fs = getNodeFs();\n\t\t\t\t\tawait fs.unlink(this.getActorAlarmPath(actorId));\n\t\t\t\t} catch (err: any) {\n\t\t\t\t\tif (err?.code !== \"ENOENT\") {\n\t\t\t\t\t\tlogger().debug({\n\t\t\t\t\t\t\tmsg: \"failed to remove alarm file\",\n\t\t\t\t\t\t\tactorId,\n\t\t\t\t\t\t\terror: stringifyError(err),\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tlogger().debug({ msg: \"triggering alarm\", actorId, timestamp });\n\n\t\t\t\t// Ensure actor state exists and start actor if needed\n\t\t\t\tconst loaded = await this.loadActor(actorId);\n\t\t\t\tif (!loaded.state)\n\t\t\t\t\tthrow new Error(`Actor does not exist: ${actorId}`);\n\n\t\t\t\t// Start actor if not already running\n\t\t\t\tconst runnerParams = this.#runnerParams;\n\t\t\t\tinvariant(runnerParams, \"missing runner params\");\n\t\t\t\tif (!loaded.actor) {\n\t\t\t\t\tawait this.startActor(\n\t\t\t\t\t\trunnerParams.registryConfig,\n\t\t\t\t\t\trunnerParams.runConfig,\n\t\t\t\t\t\trunnerParams.inlineClient,\n\t\t\t\t\t\trunnerParams.actorDriver,\n\t\t\t\t\t\tactorId,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tinvariant(loaded.actor, \"actor should be loaded after wake\");\n\t\t\t\tawait loaded.actor.onAlarm();\n\t\t\t} catch (err) {\n\t\t\t\tlogger().error({\n\t\t\t\t\tmsg: \"failed to handle alarm\",\n\t\t\t\t\tactorId,\n\t\t\t\t\terror: stringifyError(err),\n\t\t\t\t});\n\t\t\t}\n\t\t}, delay);\n\t}\n\n\tgetOrCreateInspectorAccessToken(): string {\n\t\tconst path = getNodePath();\n\t\tconst fsSync = getNodeFsSync();\n\t\tconst tokenPath = path.join(this.#storagePath, \"inspector-token\");\n\t\tif (fsSync.existsSync(tokenPath)) {\n\t\t\treturn fsSync.readFileSync(tokenPath, \"utf-8\");\n\t\t}\n\n\t\tconst newToken = generateRandomString();\n\t\tfsSync.writeFileSync(tokenPath, newToken);\n\t\treturn newToken;\n\t}\n\n\t/**\n\t * Cleanup stale temp files on startup (synchronous)\n\t */\n\t#cleanupTempFilesSync(): void {\n\t\ttry {\n\t\t\tconst fsSync = getNodeFsSync();\n\t\t\tconst files = fsSync.readdirSync(this.#stateDir);\n\t\t\tconst tempFiles = files.filter((f) => f.includes(\".tmp.\"));\n\n\t\t\tconst oneHourAgo = Date.now() - 3600000; // 1 hour in ms\n\n\t\t\tfor (const tempFile of tempFiles) {\n\t\t\t\ttry {\n\t\t\t\t\tconst path = getNodePath();\n\t\t\t\t\tconst fullPath = path.join(this.#stateDir, tempFile);\n\t\t\t\t\tconst stat = fsSync.statSync(fullPath);\n\n\t\t\t\t\t// Remove if older than 1 hour\n\t\t\t\t\tif (stat.mtimeMs < oneHourAgo) {\n\t\t\t\t\t\tfsSync.unlinkSync(fullPath);\n\t\t\t\t\t\tlogger().info({\n\t\t\t\t\t\t\tmsg: \"cleaned up stale temp file\",\n\t\t\t\t\t\t\tfile: tempFile,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tlogger().debug({\n\t\t\t\t\t\tmsg: \"failed to cleanup temp file\",\n\t\t\t\t\t\tfile: tempFile,\n\t\t\t\t\t\terror: err,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tlogger().error({\n\t\t\t\tmsg: \"failed to read actors directory for cleanup\",\n\t\t\t\terror: err,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Batch put KV entries for an actor.\n\t */\n\tasync kvBatchPut(\n\t\tactorId: string,\n\t\tentries: [Uint8Array, Uint8Array][],\n\t): Promise<void> {\n\t\tconst entry = await this.loadActor(actorId);\n\t\tif (!entry.state) {\n\t\t\tif (this.isActorStopping(actorId)) {\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\tthrow new Error(`Actor ${actorId} state not loaded`);\n\t\t\t}\n\t\t}\n\n\t\t// Create a mutable copy of kvStorage\n\t\tconst newKvStorage = [...entry.state.kvStorage];\n\n\t\t// Update kvStorage with new entries\n\t\tfor (const [key, value] of entries) {\n\t\t\t// Find existing entry with the same key\n\t\t\tconst existingIndex = newKvStorage.findIndex((e) =>\n\t\t\t\tarrayBuffersEqual(e.key, bufferToArrayBuffer(key)),\n\t\t\t);\n\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\t// Replace existing entry with new one\n\t\t\t\tnewKvStorage[existingIndex] = {\n\t\t\t\t\tkey: bufferToArrayBuffer(key),\n\t\t\t\t\tvalue: bufferToArrayBuffer(value),\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\t// Add new entry\n\t\t\t\tnewKvStorage.push({\n\t\t\t\t\tkey: bufferToArrayBuffer(key),\n\t\t\t\t\tvalue: bufferToArrayBuffer(value),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Update state with new kvStorage\n\t\tentry.state = {\n\t\t\t...entry.state,\n\t\t\tkvStorage: newKvStorage,\n\t\t};\n\n\t\t// Save state to disk\n\t\tawait this.writeActor(actorId, entry.generation, entry.state);\n\t}\n\n\t/**\n\t * Batch get KV entries for an actor.\n\t */\n\tasync kvBatchGet(\n\t\tactorId: string,\n\t\tkeys: Uint8Array[],\n\t): Promise<(Uint8Array | null)[]> {\n\t\tconst entry = await this.loadActor(actorId);\n\t\tif (!entry.state) {\n\t\t\tif (this.isActorStopping(actorId)) {\n\t\t\t\tthrow new Error(`Actor ${actorId} is stopping`);\n\t\t\t} else {\n\t\t\t\tthrow new Error(`Actor ${actorId} state not loaded`);\n\t\t\t}\n\t\t}\n\n\t\tconst results: (Uint8Array | null)[] = [];\n\t\tfor (const key of keys) {\n\t\t\t// Find entry with the same key\n\t\t\tconst foundEntry = entry.state.kvStorage.find((e) =>\n\t\t\t\tarrayBuffersEqual(e.key, bufferToArrayBuffer(key)),\n\t\t\t);\n\n\t\t\tif (foundEntry) {\n\t\t\t\tresults.push(new Uint8Array(foundEntry.value));\n\t\t\t} else {\n\t\t\t\tresults.push(null);\n\t\t\t}\n\t\t}\n\t\treturn results;\n\t}\n\n\t/**\n\t * Batch delete KV entries for an actor.\n\t */\n\tasync kvBatchDelete(actorId: string, keys: Uint8Array[]): Promise<void> {\n\t\tconst entry = await this.loadActor(actorId);\n\t\tif (!entry.state) {\n\t\t\tif (this.isActorStopping(actorId)) {\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\tthrow new Error(`Actor ${actorId} state not loaded`);\n\t\t\t}\n\t\t}\n\n\t\t// Create a mutable copy of kvStorage\n\t\tconst newKvStorage = [...entry.state.kvStorage];\n\n\t\t// Delete entries from kvStorage\n\t\tfor (const key of keys) {\n\t\t\tconst indexToDelete = newKvStorage.findIndex((e) =>\n\t\t\t\tarrayBuffersEqual(e.key, bufferToArrayBuffer(key)),\n\t\t\t);\n\n\t\t\tif (indexToDelete >= 0) {\n\t\t\t\tnewKvStorage.splice(indexToDelete, 1);\n\t\t\t}\n\t\t}\n\n\t\t// Update state with new kvStorage\n\t\tentry.state = {\n\t\t\t...entry.state,\n\t\t\tkvStorage: newKvStorage,\n\t\t};\n\n\t\t// Save state to disk\n\t\tawait this.writeActor(actorId, entry.generation, entry.state);\n\t}\n\n\t/**\n\t * List KV entries with a given prefix for an actor.\n\t */\n\tasync kvListPrefix(\n\t\tactorId: string,\n\t\tprefix: Uint8Array,\n\t): Promise<[Uint8Array, Uint8Array][]> {\n\t\tconst entry = await this.loadActor(actorId);\n\t\tif (!entry.state) {\n\t\t\tif (this.isActorStopping(actorId)) {\n\t\t\t\tthrow new Error(`Actor ${actorId} is destroying`);\n\t\t\t} else {\n\t\t\t\tthrow new Error(`Actor ${actorId} state not loaded`);\n\t\t\t}\n\t\t}\n\n\t\tconst results: [Uint8Array, Uint8Array][] = [];\n\t\tfor (const kvEntry of entry.state.kvStorage) {\n\t\t\tconst keyBytes = new Uint8Array(kvEntry.key);\n\t\t\t// Check if key starts with prefix\n\t\t\tif (keyBytes.length >= prefix.length) {\n\t\t\t\tlet hasPrefix = true;\n\t\t\t\tfor (let i = 0; i < prefix.length; i++) {\n\t\t\t\t\tif (keyBytes[i] !== prefix[i]) {\n\t\t\t\t\t\thasPrefix = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (hasPrefix) {\n\t\t\t\t\tresults.push([keyBytes, new Uint8Array(kvEntry.value)]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn results;\n\t}\n}\n","import { createVersionedDataHandler } from \"vbare\";\nimport { bufferToArrayBuffer } from \"@/utils\";\nimport * as v1 from \"../../../dist/schemas/file-system-driver/v1\";\nimport * as v2 from \"../../../dist/schemas/file-system-driver/v2\";\nimport * as v3 from \"../../../dist/schemas/file-system-driver/v3\";\n\nexport const CURRENT_VERSION = 3;\n\n// Converter from v1 to v2\nconst v1ToV2 = (v1State: v1.ActorState): v2.ActorState => {\n\t// Create a new kvStorage list with the legacy persist data\n\tconst kvStorage: v2.ActorKvEntry[] = [];\n\n\t// Store the legacy persist data under key [1]\n\tif (v1State.persistedData) {\n\t\t// Key [1] as Uint8Array\n\t\tconst key = new Uint8Array([1]);\n\t\tkvStorage.push({\n\t\t\tkey: bufferToArrayBuffer(key),\n\t\t\tvalue: v1State.persistedData,\n\t\t});\n\t}\n\n\treturn {\n\t\tactorId: v1State.actorId,\n\t\tname: v1State.name,\n\t\tkey: v1State.key,\n\t\tkvStorage,\n\t\tcreatedAt: v1State.createdAt,\n\t};\n};\n\n// Converter from v2 to v3\nconst v2ToV3 = (v2State: v2.ActorState): v3.ActorState => {\n\t// Migrate from v2 to v3 by adding the new optional timestamp fields\n\treturn {\n\t\tactorId: v2State.actorId,\n\t\tname: v2State.name,\n\t\tkey: v2State.key,\n\t\tkvStorage: v2State.kvStorage,\n\t\tcreatedAt: v2State.createdAt,\n\t\tstartTs: null,\n\t\tconnectableTs: null,\n\t\tsleepTs: null,\n\t\tdestroyTs: null,\n\t};\n};\n\n// Converter from v3 to v2\nconst v3ToV2 = (v3State: v3.ActorState): v2.ActorState => {\n\t// Downgrade from v3 to v2 by removing the timestamp fields\n\treturn {\n\t\tactorId: v3State.actorId,\n\t\tname: v3State.name,\n\t\tkey: v3State.key,\n\t\tkvStorage: v3State.kvStorage,\n\t\tcreatedAt: v3State.createdAt,\n\t};\n};\n\n// Converter from v2 to v1\nconst v2ToV1 = (v2State: v2.ActorState): v1.ActorState => {\n\t// Downgrade from v2 to v1 by converting kvStorage back to persistedData\n\t// Find the persist data entry (key [1])\n\tconst persistDataEntry = v2State.kvStorage.find((entry) => {\n\t\tconst key = new Uint8Array(entry.key);\n\t\treturn key.length === 1 && key[0] === 1;\n\t});\n\n\treturn {\n\t\tactorId: v2State.actorId,\n\t\tname: v2State.name,\n\t\tkey: v2State.key,\n\t\tpersistedData: persistDataEntry?.value || new ArrayBuffer(0),\n\t\tcreatedAt: v2State.createdAt,\n\t};\n};\n\nexport const ACTOR_STATE_VERSIONED = createVersionedDataHandler<v3.ActorState>({\n\tdeserializeVersion: (bytes, version) => {\n\t\tswitch (version) {\n\t\t\tcase 1:\n\t\t\t\treturn v1.decodeActorState(bytes);\n\t\t\tcase 2:\n\t\t\t\treturn v2.decodeActorState(bytes);\n\t\t\tcase 3:\n\t\t\t\treturn v3.decodeActorState(bytes);\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unknown version ${version}`);\n\t\t}\n\t},\n\tserializeVersion: (data, version) => {\n\t\tswitch (version) {\n\t\t\tcase 1:\n\t\t\t\treturn v1.encodeActorState(data as v1.ActorState);\n\t\t\tcase 2:\n\t\t\t\treturn v2.encodeActorState(data as v2.ActorState);\n\t\t\tcase 3:\n\t\t\t\treturn v3.encodeActorState(data as v3.ActorState);\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unknown version ${version}`);\n\t\t}\n\t},\n\tdeserializeConverters: () => [v1ToV2, v2ToV3],\n\tserializeConverters: () => [v3ToV2, v2ToV1],\n});\n\nexport const ACTOR_ALARM_VERSIONED = createVersionedDataHandler<v3.ActorAlarm>({\n\tdeserializeVersion: (bytes, version) => {\n\t\tswitch (version) {\n\t\t\tcase 1:\n\t\t\t\treturn v1.decodeActorAlarm(bytes);\n\t\t\tcase 2:\n\t\t\t\treturn v2.decodeActorAlarm(bytes);\n\t\t\tcase 3:\n\t\t\t\treturn v3.decodeActorAlarm(bytes);\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unknown version ${version}`);\n\t\t}\n\t},\n\tserializeVersion: (data, version) => {\n\t\tswitch (version) {\n\t\t\tcase 1:\n\t\t\t\treturn v1.encodeActorAlarm(data as v1.ActorAlarm);\n\t\t\tcase 2:\n\t\t\t\treturn v2.encodeActorAlarm(data as v2.ActorAlarm);\n\t\t\tcase 3:\n\t\t\t\treturn v3.encodeActorAlarm(data as v3.ActorAlarm);\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unknown version ${version}`);\n\t\t}\n\t},\n\tdeserializeConverters: () => [],\n\tserializeConverters: () => [],\n});\n","import * as bare from \"@bare-ts/lib\"\n\nconst config = /* @__PURE__ */ bare.Config({})\n\nexport type u64 = bigint\nexport type uint = bigint\n\nfunction read0(bc: bare.ByteCursor): readonly string[] {\n const len = bare.readUintSafe(bc)\n if (len === 0) { return [] }\n const result = [bare.readString(bc)]\n for (let i = 1; i < len; i++) {\n result[i] = bare.readString(bc)\n }\n return result\n}\n\nfunction write0(bc: bare.ByteCursor, x: readonly string[]): void {\n bare.writeUintSafe(bc, x.length)\n for (let i = 0; i < x.length; i++) {\n bare.writeString(bc, x[i])\n }\n}\n\nexport type ActorState = {\n readonly actorId: string,\n readonly name: string,\n readonly key: readonly string[],\n readonly persistedData: ArrayBuffer,\n readonly createdAt: u64,\n}\n\nexport function readActorState(bc: bare.ByteCursor): ActorState {\n return {\n actorId: bare.readString(bc),\n name: bare.readString(bc),\n key: read0(bc),\n persistedData: bare.readData(bc),\n createdAt: bare.readU64(bc),\n }\n}\n\nexport function writeActorState(bc: bare.ByteCursor, x: ActorState): void {\n bare.writeString(bc, x.actorId)\n bare.writeString(bc, x.name)\n write0(bc, x.key)\n bare.writeData(bc, x.persistedData)\n bare.writeU64(bc, x.createdAt)\n}\n\nexport function encodeActorState(x: ActorState): Uint8Array {\n const bc = new bare.ByteCursor(\n new Uint8Array(config.initialBufferLength),\n config\n )\n writeActorState(bc, x)\n return new Uint8Array(bc.view.buffer, bc.view.byteOffset, bc.offset)\n}\n\nexport function decodeActorState(bytes: Uint8Array): ActorState {\n const bc = new bare.ByteCursor(bytes, config)\n const result = readActorState(bc)\n if (bc.offset < bc.view.byteLength) {\n throw new bare.BareError(bc.offset, \"remaining bytes\")\n }\n return result\n}\n\nexport type ActorAlarm = {\n readonly actorId: string,\n readonly timestamp: uint,\n}\n\nexport function readActorAlarm(bc: bare.ByteCursor): ActorAlarm {\n return {\n actorId: bare.readString(bc),\n timestamp: bare.readUint(bc),\n }\n}\n\nexport function writeActorAlarm(bc: bare.ByteCursor, x: ActorAlarm): void {\n bare.writeString(bc, x.actorId)\n bare.writeUint(bc, x.timestamp)\n}\n\nexport function encodeActorAlarm(x: ActorAlarm): Uint8Array {\n const bc = new bare.ByteCursor(\n new Uint8Array(config.initialBufferLength),\n config\n )\n writeActorAlarm(bc, x)\n return new Uint8Array(bc.view.buffer, bc.view.byteOffset, bc.offset)\n}\n\nexport function decodeActorAlarm(bytes: Uint8Array): ActorAlarm {\n const bc = new bare.ByteCursor(bytes, config)\n const result = readActorAlarm(bc)\n if (bc.offset < bc.view.byteLength) {\n throw new bare.BareError(bc.offset, \"remaining bytes\")\n }\n return result\n}\n\n\nfunction assert(condition: boolean, message?: string): asserts condition {\n if (!condition) throw new Error(message ?? \"Assertion failed\")\n}\n\n","import * as bare from \"@bare-ts/lib\"\n\nconst config = /* @__PURE__ */ bare.Config({})\n\nexport type u64 = bigint\nexport type uint = bigint\n\nexport type ActorKvEntry = {\n readonly key: ArrayBuffer,\n readonly value: ArrayBuffer,\n}\n\nexport function readActorKvEntry(bc: bare.ByteCursor): ActorKvEntry {\n return {\n key: bare.readData(bc),\n value: bare.readData(bc),\n }\n}\n\nexport function writeActorKvEntry(bc: bare.ByteCursor, x: ActorKvEntry): void {\n bare.writeData(bc, x.key)\n bare.writeData(bc, x.value)\n}\n\nfunction read0(bc: bare.ByteCursor): readonly string[] {\n const len = bare.readUintSafe(bc)\n if (len === 0) { return [] }\n const result = [bare.readString(bc)]\n for (let i = 1; i < len; i++) {\n result[i] = bare.readString(bc)\n }\n return result\n}\n\nfunction write0(bc: bare.ByteCursor, x: readonly string[]): void {\n bare.writeUintSafe(bc, x.length)\n for (let i = 0; i < x.length; i++) {\n bare.writeString(bc, x[i])\n }\n}\n\nfunction read1(bc: bare.ByteCursor): readonly ActorKvEntry[] {\n const len = bare.readUintSafe(bc)\n if (len === 0) { return [] }\n const result = [readActorKvEntry(bc)]\n for (let i = 1; i < len; i++) {\n result[i] = readActorKvEntry(bc)\n }\n return result\n}\n\nfunction write1(bc: bare.ByteCursor, x: readonly ActorKvEntry[]): void {\n bare.writeUintSafe(bc, x.length)\n for (let i = 0; i < x.length; i++) {\n writeActorKvEntry(bc, x[i])\n }\n}\n\nexport type ActorState = {\n readonly actorId: string,\n readonly name: string,\n readonly key: readonly string[],\n readonly kvStorage: readonly ActorKvEntry[],\n readonly createdAt: u64,\n}\n\nexport function readActorState(bc: bare.ByteCursor): ActorState {\n return {\n actorId: bare.readString(bc),\n name: bare.readString(bc),\n key: read0(bc),\n kvStorage: read1(bc),\n createdAt: bare.readU64(bc),\n }\n}\n\nexport function writeActorState(bc: bare.ByteCursor, x: ActorState): void {\n bare.writeString(bc, x.actorId)\n bare.writeString(bc, x.name)\n write0(bc, x.key)\n write1(bc, x.kvStorage)\n bare.writeU64(bc, x.createdAt)\n}\n\nexport function encodeActorState(x: ActorState): Uint8Array {\n const bc = new bare.ByteCursor(\n new Uint8Array(config.initialBufferLength),\n config\n )\n writeActorState(bc, x)\n return new Uint8Array(bc.view.buffer, bc.view.byteOffset, bc.offset)\n}\n\nexport function decodeActorState(bytes: Uint8Array): ActorState {\n const bc = new bare.ByteCursor(bytes, config)\n const result = readActorState(bc)\n if (bc.offset < bc.view.byteLength) {\n throw new bare.BareError(bc.offset, \"remaining bytes\")\n }\n return result\n}\n\nexport type ActorAlarm = {\n readonly actorId: string,\n readonly timestamp: uint,\n}\n\nexport function readActorAlarm(bc: bare.ByteCursor): ActorAlarm {\n return {\n actorId: bare.readString(bc),\n timestamp: bare.readUint(bc),\n }\n}\n\nexport function writeActorAlarm(bc: bare.ByteCursor, x: ActorAlarm): void {\n bare.writeString(bc, x.actorId)\n bare.writeUint(bc, x.timestamp)\n}\n\nexport function encodeActorAlarm(x: ActorAlarm): Uint8Array {\n const bc = new bare.ByteCursor(\n new Uint8Array(config.initialBufferLength),\n config\n )\n writeActorAlarm(bc, x)\n return new Uint8Array(bc.view.buffer, bc.view.byteOffset, bc.offset)\n}\n\nexport function decodeActorAlarm(bytes: Uint8Array): ActorAlarm {\n const bc = new bare.ByteCursor(bytes, config)\n const result = readActorAlarm(bc)\n if (bc.offset < bc.view.byteLength) {\n throw new bare.BareError(bc.offset, \"remaining bytes\")\n }\n return result\n}\n\n\nfunction assert(condition: boolean, message?: string): asserts condition {\n if (!condition) throw new Error(message ?? \"Assertion failed\")\n}\n\n","import * as bare from \"@bare-ts/lib\"\n\nconst config = /* @__PURE__ */ bare.Config({})\n\nexport type u64 = bigint\nexport type uint = bigint\n\nexport type ActorKvEntry = {\n readonly key: ArrayBuffer,\n readonly value: ArrayBuffer,\n}\n\nexport function readActorKvEntry(bc: bare.ByteCursor): ActorKvEntry {\n return {\n key: bare.readData(bc),\n value: bare.readData(bc),\n }\n}\n\nexport function writeActorKvEntry(bc: bare.ByteCursor, x: ActorKvEntry): void {\n bare.writeData(bc, x.key)\n bare.writeData(bc, x.value)\n}\n\nfunction read0(bc: bare.ByteCursor): readonly string[] {\n const len = bare.readUintSafe(bc)\n if (len === 0) { return [] }\n const result = [bare.readString(bc)]\n for (let i = 1; i < len; i++) {\n result[i] = bare.readString(bc)\n }\n return result\n}\n\nfunction write0(bc: bare.ByteCursor, x: readonly string[]): void {\n bare.writeUintSafe(bc, x.length)\n for (let i = 0; i < x.length; i++) {\n bare.writeString(bc, x[i])\n }\n}\n\nfunction read1(bc: bare.ByteCursor): readonly ActorKvEntry[] {\n const len = bare.readUintSafe(bc)\n if (len === 0) { return [] }\n const result = [readActorKvEntry(bc)]\n for (let i = 1; i < len; i++) {\n result[i] = readActorKvEntry(bc)\n }\n return result\n}\n\nfunction write1(bc: bare.ByteCursor, x: readonly ActorKvEntry[]): void {\n bare.writeUintSafe(bc, x.length)\n for (let i = 0; i < x.length; i++) {\n writeActorKvEntry(bc, x[i])\n }\n}\n\nfunction read2(bc: bare.ByteCursor): u64 | null {\n return bare.readBool(bc)\n ? bare.readU64(bc)\n : null\n}\n\nfunction write2(bc: bare.ByteCursor, x: u64 | null): void {\n bare.writeBool(bc, x !== null)\n if (x !== null) {\n bare.writeU64(bc, x)\n }\n}\n\nexport type ActorState = {\n readonly actorId: string,\n readonly name: string,\n readonly key: readonly string[],\n readonly kvStorage: readonly ActorKvEntry[],\n readonly createdAt: u64,\n readonly startTs: u64 | null,\n readonly connectableTs: u64 | null,\n readonly sleepTs: u64 | null,\n readonly destroyTs: u64 | null,\n}\n\nexport function readActorState(bc: bare.ByteCursor): ActorState {\n return {\n actorId: bare.readString(bc),\n name: bare.readString(bc),\n key: read0(bc),\n kvStorage: read1(bc),\n createdAt: bare.readU64(bc),\n startTs: read2(bc),\n connectableTs: read2(bc),\n sleepTs: read2(bc),\n destroyTs: read2(bc),\n }\n}\n\nexport function writeActorState(bc: bare.ByteCursor, x: ActorState): void {\n bare.writeString(bc, x.actorId)\n bare.writeString(bc, x.name)\n write0(bc, x.key)\n write1(bc, x.kvStorage)\n bare.writeU64(bc, x.createdAt)\n write2(bc, x.startTs)\n write2(bc, x.connectableTs)\n write2(bc, x.sleepTs)\n write2(bc, x.destroyTs)\n}\n\nexport function encodeActorState(x: ActorState): Uint8Array {\n const bc = new bare.ByteCursor(\n new Uint8Array(config.initialBufferLength),\n config\n )\n writeActorState(bc, x)\n return new Uint8Array(bc.view.buffer, bc.view.byteOffset, bc.offset)\n}\n\nexport function decodeActorState(bytes: Uint8Array): ActorState {\n const bc = new bare.ByteCursor(bytes, config)\n const result = readActorState(bc)\n if (bc.offset < bc.view.byteLength) {\n throw new bare.BareError(bc.offset, \"remaining bytes\")\n }\n return result\n}\n\nexport type ActorAlarm = {\n readonly actorId: string,\n readonly timestamp: uint,\n}\n\nexport function readActorAlarm(bc: bare.ByteCursor): ActorAlarm {\n return {\n actorId: bare.readString(bc),\n timestamp: bare.readUint(bc),\n }\n}\n\nexport function writeActorAlarm(bc: bare.ByteCursor, x: ActorAlarm): void {\n bare.writeString(bc, x.actorId)\n bare.writeUint(bc, x.timestamp)\n}\n\nexport function encodeActorAlarm(x: ActorAlarm): Uint8Array {\n const bc = new bare.ByteCursor(\n new Uint8Array(config.initialBufferLength),\n config\n )\n writeActorAlarm(bc, x)\n return new Uint8Array(bc.view.buffer, bc.view.byteOffset, bc.offset)\n}\n\nexport function decodeActorAlarm(bytes: Uint8Array): ActorAlarm {\n const bc = new bare.ByteCursor(bytes, config)\n const result = readActorAlarm(bc)\n if (bc.offset < bc.view.byteLength) {\n throw new bare.BareError(bc.offset, \"remaining bytes\")\n }\n return result\n}\n\n\nfunction assert(condition: boolean, message?: string): asserts condition {\n if (!condition) throw new Error(message ?? \"Assertion failed\")\n}\n\n","import { getLogger } from \"@/common/log\";\n\nexport function logger() {\n\treturn getLogger(\"driver-fs\");\n}\n","import type { ActorKey } from \"@/actor/mod\";\nimport {\n\tgetNodeCrypto,\n\tgetNodeFs,\n\tgetNodeFsSync,\n\tgetNodeOs,\n\tgetNodePath,\n} from \"@/utils/node\";\n\n/**\n * Generate a deterministic actor ID from name and key\n */\nexport function generateActorId(name: string, key: ActorKey): string {\n\t// Generate deterministic key string\n\tconst jsonString = JSON.stringify([name, key]);\n\n\t// Hash to ensure safe file system names\n\tconst crypto = getNodeCrypto();\n\tconst hash = crypto\n\t\t.createHash(\"sha256\")\n\t\t.update(jsonString)\n\t\t.digest(\"hex\")\n\t\t.substring(0, 16);\n\n\treturn hash;\n}\n\n/**\n * Create a hash for a path, normalizing it first\n */\nfunction createHashForPath(dirPath: string): string {\n\tconst path = getNodePath();\n\t// Normalize the path first\n\tconst normalizedPath = path.normalize(dirPath);\n\n\t// Extract the last path component for readability\n\tconst lastComponent = path.basename(normalizedPath);\n\n\t// Create SHA-256 hash\n\tconst crypto = getNodeCrypto();\n\tconst hash = crypto\n\t\t.createHash(\"sha256\")\n\t\t.update(normalizedPath)\n\t\t.digest(\"hex\")\n\t\t.substring(0, 8); // Take first 8 characters for brevity\n\n\treturn `${lastComponent}-${hash}`;\n}\n\n/**\n * Get the storage path for the current working directory or a specified path\n */\nexport function getStoragePath(): string {\n\tconst dataPath = getDataPath(\"rivetkit\");\n\tconst dirHash = createHashForPath(process.cwd());\n\tconst path = getNodePath();\n\treturn path.join(dataPath, dirHash);\n}\n\n/**\n * Check if a path exists\n */\nexport async function pathExists(path: string): Promise<boolean> {\n\ttry {\n\t\tconst fs = getNodeFs();\n\t\tawait fs.access(path);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Ensure a directory exists, creating it if necessary\n */\nexport async function ensureDirectoryExists(\n\tdirectoryPath: string,\n): Promise<void> {\n\tif (!(await pathExists(directoryPath))) {\n\t\tconst fs = getNodeFs();\n\t\tawait fs.mkdir(directoryPath, { recursive: true });\n\t}\n}\n\n/**\n * Ensure a directory exists synchronously - only used during initialization\n * All other operations use the async version\n */\nexport function ensureDirectoryExistsSync(directoryPath: string): void {\n\tconst fsSync = getNodeFsSync();\n\tif (!fsSync.existsSync(directoryPath)) {\n\t\tfsSync.mkdirSync(directoryPath, { recursive: true });\n\t}\n}\n\n/**\n * Returns platform-specific data directory\n */\nfunction getDataPath(appName: string): string {\n\tconst platform = process.platform;\n\tconst os = getNodeOs();\n\tconst homeDir = os.homedir();\n\tconst path = getNodePath();\n\n\tswitch (platform) {\n\t\tcase \"win32\":\n\t\t\treturn path.join(\n\t\t\t\tprocess.env.APPDATA || path.join(homeDir, \"AppData\", \"Roaming\"),\n\t\t\t\tappName,\n\t\t\t);\n\t\tcase \"darwin\":\n\t\t\treturn path.join(\n\t\t\t\thomeDir,\n\t\t\t\t\"Library\",\n\t\t\t\t\"Application Support\",\n\t\t\t\tappName,\n\t\t\t);\n\t\tdefault: // linux and others\n\t\t\treturn path.join(\n\t\t\t\tprocess.env.XDG_DATA_HOME ||\n\t\t\t\t\tpath.join(homeDir, \".local\", \"share\"),\n\t\t\t\tappName,\n\t\t\t);\n\t}\n}\n","import type { Context as HonoContext } from \"hono\";\nimport invariant from \"invariant\";\nimport { ActorStopping } from \"@/actor/errors\";\nimport { type ActorRouter, createActorRouter } from \"@/actor/router\";\nimport { routeWebSocket } from \"@/actor/router-websocket-endpoints\";\nimport { createClientWithDriver } from \"@/client/client\";\nimport { ClientConfigSchema } from \"@/client/config\";\nimport { InlineWebSocketAdapter } from \"@/common/inline-websocket-adapter\";\nimport { noopNext } from \"@/common/utils\";\nimport type {\n\tActorDriver,\n\tActorOutput,\n\tCreateInput,\n\tGetForIdInput,\n\tGetOrCreateWithKeyInput,\n\tGetWithKeyInput,\n\tListActorsInput,\n\tManagerDriver,\n} from \"@/driver-helpers/mod\";\nimport { ManagerInspector } from \"@/inspector/manager\";\nimport { type Actor, ActorFeature, type ActorId } from \"@/inspector/mod\";\nimport type { ManagerDisplayInformation } from \"@/manager/driver\";\nimport type {\n\tDriverConfig,\n\tEncoding,\n\tRegistryConfig,\n\tRunConfig,\n\tUniversalWebSocket,\n} from \"@/mod\";\nimport type * as schema from \"@/schemas/file-system-driver/mod\";\nimport type { FileSystemGlobalState } from \"./global-state\";\nimport { logger } from \"./log\";\nimport { generateActorId } from \"./utils\";\n\nexport class FileSystemManagerDriver implements ManagerDriver {\n\t#registryConfig: RegistryConfig;\n\t#runConfig: RunConfig;\n\t#state: FileSystemGlobalState;\n\t#driverConfig: DriverConfig;\n\n\t#actorDriver: ActorDriver;\n\t#actorRouter: ActorRouter;\n\n\tinspector?: ManagerInspector;\n\n\tconstructor(\n\t\tregistryConfig: RegistryConfig,\n\t\trunConfig: RunConfig,\n\t\tstate: FileSystemGlobalState,\n\t\tdriverConfig: DriverConfig,\n\t) {\n\t\tthis.#registryConfig = registryConfig;\n\t\tthis.#runConfig = runConfig;\n\t\tthis.#state = state;\n\t\tthis.#driverConfig = driverConfig;\n\n\t\tif (runConfig.inspector.enabled) {\n\t\t\tconst startedAt = new Date().toISOString();\n\t\t\tfunction transformActor(actorState: schema.ActorState): Actor {\n\t\t\t\treturn {\n\t\t\t\t\tid: actorState.actorId as ActorId,\n\t\t\t\t\tname: actorState.name,\n\t\t\t\t\tkey: actorState.key as string[],\n\t\t\t\t\tstartedAt: startedAt,\n\t\t\t\t\tcreatedAt: new Date(\n\t\t\t\t\t\tNumber(actorState.createdAt),\n\t\t\t\t\t).toISOString(),\n\t\t\t\t\tfeatures: [\n\t\t\t\t\t\tActorFeature.State,\n\t\t\t\t\t\tActorFeature.Connections,\n\t\t\t\t\t\tActorFeature.Console,\n\t\t\t\t\t\tActorFeature.EventsMonitoring,\n\t\t\t\t\t\tActorFeature.Database,\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tthis.inspector = new ManagerInspector(() => {\n\t\t\t\treturn {\n\t\t\t\t\tgetAllActors: async ({ cursor, limit }) => {\n\t\t\t\t\t\tconst itr = this.#state.getActorsIterator({ cursor });\n\t\t\t\t\t\tconst actors: Actor[] = [];\n\n\t\t\t\t\t\tfor await (const actor of itr) {\n\t\t\t\t\t\t\tactors.push(transformActor(actor));\n\t\t\t\t\t\t\tif (limit && actors.length >= limit) {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn actors;\n\t\t\t\t\t},\n\t\t\t\t\tgetActorById: async (id) => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst result =\n\t\t\t\t\t\t\t\tawait this.#state.loadActorStateOrError(id);\n\t\t\t\t\t\t\treturn transformActor(result);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tgetBuilds: async () => {\n\t\t\t\t\t\treturn Object.keys(this.#registryConfig.use).map(\n\t\t\t\t\t\t\t(name) => ({\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t\tcreateActor: async (input) => {\n\t\t\t\t\t\tconst { actorId } = await this.createActor(input);\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst result =\n\t\t\t\t\t\t\t\tawait this.#state.loadActorStateOrError(\n\t\t\t\t\t\t\t\t\tactorId,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn transformActor(result);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t});\n\t\t}\n\n\t\t// Actors run on the same node as the manager, so we create a dummy actor router that we route requests to\n\t\tconst inlineClient = createClientWithDriver(\n\t\t\tthis,\n\t\t\tClientConfigSchema.parse({}),\n\t\t);\n\t\tthis.#actorDriver = this.#driverConfig.actor(\n\t\t\tregistryConfig,\n\t\t\trunConfig,\n\t\t\tthis,\n\t\t\tinlineClient,\n\t\t);\n\t\tthis.#actorRouter = createActorRouter(\n\t\t\tthis.#runConfig,\n\t\t\tthis.#actorDriver,\n\t\t\tregistryConfig.test.enabled,\n\t\t);\n\t}\n\n\tasync sendRequest(\n\t\tactorId: string,\n\t\tactorRequest: Request,\n\t): Promise<Response> {\n\t\treturn await this.#actorRouter.fetch(actorRequest, {\n\t\t\tactorId,\n\t\t});\n\t}\n\n\tasync openWebSocket(\n\t\tpath: string,\n\t\tactorId: string,\n\t\tencoding: Encoding,\n\t\tparams: unknown,\n\t): Promise<UniversalWebSocket> {\n\t\t// Handle raw WebSocket paths\n\t\tconst pathOnly = path.split(\"?\")[0];\n\t\tconst normalizedPath = pathOnly.startsWith(\"/\")\n\t\t\t? pathOnly\n\t\t\t: `/${pathOnly}`;\n\t\tconst wsHandler = await routeWebSocket(\n\t\t\t// TODO: Create fake request\n\t\t\tundefined,\n\t\t\tnormalizedPath,\n\t\t\t{},\n\t\t\tthis.#runConfig,\n\t\t\tthis.#actorDriver,\n\t\t\tactorId,\n\t\t\tencoding,\n\t\t\tparams,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tfalse,\n\t\t\tfalse,\n\t\t);\n\t\treturn new InlineWebSocketAdapter(wsHandler);\n\t}\n\n\tasync proxyRequest(\n\t\tc: HonoContext,\n\t\tactorRequest: Request,\n\t\tactorId: string,\n\t): Promise<Response> {\n\t\treturn await this.#actorRouter.fetch(actorRequest, {\n\t\t\tactorId,\n\t\t});\n\t}\n\n\tasync proxyWebSocket(\n\t\tc: HonoContext,\n\t\tpath: string,\n\t\tactorId: string,\n\t\tencoding: Encoding,\n\t\tparams: unknown,\n\t): Promise<Response> {\n\t\tconst upgradeWebSocket = this.#runConfig.getUpgradeWebSocket?.();\n\t\tinvariant(upgradeWebSocket, \"missing getUpgradeWebSocket\");\n\n\t\t// Handle raw WebSocket paths\n\t\tconst pathOnly = path.split(\"?\")[0];\n\t\tconst normalizedPath = pathOnly.startsWith(\"/\")\n\t\t\t? pathOnly\n\t\t\t: `/${pathOnly}`;\n\t\tconst wsHandler = await routeWebSocket(\n\t\t\t// TODO: Create new request with new path\n\t\t\tc.req.raw,\n\t\t\tnormalizedPath,\n\t\t\tc.req.header(),\n\t\t\tthis.#runConfig,\n\t\t\tthis.#actorDriver,\n\t\t\tactorId,\n\t\t\tencoding,\n\t\t\tparams,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tfalse,\n\t\t\tfalse,\n\t\t);\n\t\treturn upgradeWebSocket(() => wsHandler)(c, noopNext());\n\t}\n\n\tasync getForId({\n\t\tactorId,\n\t}: GetForIdInput): Promise<ActorOutput | undefined> {\n\t\t// Validate the actor exists\n\t\tconst actor = await this.#state.loadActor(actorId);\n\t\tif (!actor.state) {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (this.#state.isActorStopping(actorId)) {\n\t\t\tthrow new ActorStopping(actorId);\n\t\t}\n\n\t\ttry {\n\t\t\t// Load actor state\n\t\t\treturn {\n\t\t\t\tactorId,\n\t\t\t\tname: actor.state.name,\n\t\t\t\tkey: actor.state.key as string[],\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tlogger().error({\n\t\t\t\tmsg: \"failed to read actor state\",\n\t\t\t\tactorId,\n\t\t\t\terror,\n\t\t\t});\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tasync getWithKey({\n\t\tname,\n\t\tkey,\n\t}: GetWithKeyInput): Promise<ActorOutput | undefined> {\n\t\t// Generate the deterministic actor ID\n\t\tconst actorId = generateActorId(name, key);\n\n\t\t// Check if actor exists\n\t\tconst actor = await this.#state.loadActor(actorId);\n\t\tif (actor.state) {\n\t\t\treturn {\n\t\t\t\tactorId,\n\t\t\t\tname,\n\t\t\t\tkey,\n\t\t\t};\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tasync getOrCreateWithKey(\n\t\tinput: GetOrCreateWithKeyInput,\n\t): Promise<ActorOutput> {\n\t\t// Generate the deterministic actor ID\n\t\tconst actorId = generateActorId(input.name, input.key);\n\n\t\t// Use the atomic getOrCreateActor method\n\t\tconst actorEntry = await this.#state.loadOrCreateActor(\n\t\t\tactorId,\n\t\t\tinput.name,\n\t\t\tinput.key,\n\t\t\tinput.input,\n\t\t);\n\t\tinvariant(actorEntry.state, \"must have state\");\n\n\t\treturn {\n\t\t\tactorId: actorEntry.state.actorId,\n\t\t\tname: actorEntry.state.name,\n\t\t\tkey: actorEntry.state.key as string[],\n\t\t};\n\t}\n\n\tasync createActor({ name, key, input }: CreateInput): Promise<ActorOutput> {\n\t\t// Generate the deterministic actor ID\n\t\tconst actorId = generateActorId(name, key);\n\n\t\tawait this.#state.createActor(actorId, name, key, input);\n\n\t\treturn {\n\t\t\tactorId,\n\t\t\tname,\n\t\t\tkey,\n\t\t};\n\t}\n\n\tasync listActors({ name }: ListActorsInput): Promise<ActorOutput[]> {\n\t\tconst actors: ActorOutput[] = [];\n\t\tconst itr = this.#state.getActorsIterator({});\n\n\t\tfor await (const actor of itr) {\n\t\t\tif (actor.name === name) {\n\t\t\t\tactors.push({\n\t\t\t\t\tactorId: actor.actorId,\n\t\t\t\t\tname: actor.name,\n\t\t\t\t\tkey: actor.key as string[],\n\t\t\t\t\tcreateTs: Number(actor.createdAt),\n\t\t\t\t\tstartTs: actor.startTs !== null ? Number(actor.startTs) : null,\n\t\t\t\t\tconnectableTs: actor.connectableTs !== null ? Number(actor.connectableTs) : null,\n\t\t\t\t\tsleepTs: actor.sleepTs !== null ? Number(actor.sleepTs) : null,\n\t\t\t\t\tdestroyTs: actor.destroyTs !== null ? Number(actor.destroyTs) : null,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Sort by create ts desc (most recent first)\n\t\tactors.sort((a, b) => {\n\t\t\tconst aTs = a.createTs ?? 0;\n\t\t\tconst bTs = b.createTs ?? 0;\n\t\t\treturn bTs - aTs;\n\t\t});\n\n\t\treturn actors;\n\t}\n\n\tdisplayInformation(): ManagerDisplayInformation {\n\t\treturn {\n\t\t\tname: this.#state.persist ? \"File System\" : \"Memory\",\n\t\t\tproperties: {\n\t\t\t\t...(this.#state.persist\n\t\t\t\t\t? { Data: this.#state.storagePath }\n\t\t\t\t\t: {}),\n\t\t\t\tInstances: this.#state.actorCountOnStartup.toString(),\n\t\t\t},\n\t\t};\n\t}\n\n\textraStartupLog() {\n\t\treturn {\n\t\t\tinstances: this.#state.actorCountOnStartup,\n\t\t\tdata: this.#state.storagePath,\n\t\t};\n\t}\n\n\tgetOrCreateInspectorAccessToken() {\n\t\treturn this.#state.getOrCreateInspectorAccessToken();\n\t}\n}\n","import { sValidator } from \"@hono/standard-validator\";\nimport { Hono } from \"hono\";\nimport invariant from \"invariant\";\nimport type { CreateInput } from \"@/manager/driver\";\nimport { inspectorLogger } from \"./log\";\nimport { type Actor, type Builds, CreateActorSchema } from \"./protocol/common\";\n\nexport type ManagerInspectorRouterEnv = {\n\tVariables: {\n\t\tinspector: ManagerInspector;\n\t};\n};\n\n/**\n * Create a router for the Manager Inspector.\n * @internal\n */\nexport function createManagerInspectorRouter() {\n\treturn new Hono<ManagerInspectorRouterEnv>()\n\t\t.get(\"/ping\", (c) => {\n\t\t\treturn c.json({ message: \"pong\" }, 200);\n\t\t})\n\t\t.get(\"/actors\", async (c) => {\n\t\t\tconst limit =\n\t\t\t\tNumber.parseInt(c.req.query(\"limit\") ?? \"\") || undefined;\n\t\t\tconst cursor = c.req.query(\"cursor\") || undefined;\n\n\t\t\tif (!limit || (limit && limit <= 0)) {\n\t\t\t\treturn c.json(\"Invalid limit\", 400);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst actors = await c.var.inspector.accessors.getAllActors({\n\t\t\t\t\tlimit,\n\t\t\t\t\tcursor,\n\t\t\t\t});\n\t\t\t\treturn c.json(actors, 200);\n\t\t\t} catch (error) {\n\t\t\t\tinspectorLogger().error({\n\t\t\t\t\tmsg: \"Failed to fetch actors\",\n\t\t\t\t\terror,\n\t\t\t\t});\n\t\t\t\treturn c.json(\"Failed to fetch actors\", 500);\n\t\t\t}\n\t\t})\n\n\t\t.post(\"/actors\", sValidator(\"json\", CreateActorSchema), async (c) => {\n\t\t\tconst actor = await c.var.inspector.accessors.createActor(\n\t\t\t\tc.req.valid(\"json\"),\n\t\t\t);\n\t\t\treturn c.json(actor, 201);\n\t\t})\n\t\t.get(\"/builds\", async (c) => {\n\t\t\tconst builds = await c.var.inspector.accessors.getBuilds();\n\t\t\treturn c.json(builds, 200);\n\t\t})\n\t\t.get(\"/actor/:id\", async (c) => {\n\t\t\tconst id = c.req.param(\"id\");\n\t\t\tconst actor = await c.var.inspector.accessors.getActorById(id);\n\t\t\tif (!actor) {\n\t\t\t\treturn c.json({ error: \"Actor not found\" }, 404);\n\t\t\t}\n\t\t\treturn c.json(actor, 200);\n\t\t})\n\t\t.get(\"/bootstrap\", async (c) => {\n\t\t\tconst actors = await c.var.inspector.accessors.getAllActors({\n\t\t\t\tlimit: 10,\n\t\t\t});\n\t\t\treturn c.json({ actors }, 200);\n\t\t});\n}\n\ninterface ManagerInspectorAccessors {\n\tgetAllActors: (param: {\n\t\tcursor?: string;\n\t\tlimit: number;\n\t}) => Promise<Actor[]>;\n\tgetActorById: (id: string) => Promise<Actor | null>;\n\tgetBuilds: () => Promise<Builds>;\n\tcreateActor: (input: CreateInput) => Promise<Actor | null>;\n}\n\n/**\n * Provides a unified interface for inspecting actor external and internal state.\n */\nexport class ManagerInspector {\n\tpublic readonly accessors: ManagerInspectorAccessors;\n\n\tconstructor(accessors: () => ManagerInspectorAccessors) {\n\t\tthis.accessors = accessors();\n\t\tinspectorLogger().debug({ msg: \"Manager Inspector enabled and ready\" });\n\t}\n}\n","import type { DriverConfig } from \"@/registry/run-config\";\nimport { importNodeDependencies } from \"@/utils/node\";\nimport { FileSystemActorDriver } from \"./actor\";\nimport { FileSystemGlobalState } from \"./global-state\";\nimport { FileSystemManagerDriver } from \"./manager\";\n\nexport { FileSystemActorDriver } from \"./actor\";\nexport { FileSystemGlobalState } from \"./global-state\";\nexport { FileSystemManagerDriver } from \"./manager\";\nexport { getStoragePath } from \"./utils\";\n\nexport function createFileSystemOrMemoryDriver(\n\tpersist: boolean = true,\n\tcustomPath?: string,\n): DriverConfig {\n\timportNodeDependencies();\n\n\tconst state = new FileSystemGlobalState(persist, customPath);\n\tconst driverConfig: DriverConfig = {\n\t\tname: persist ? \"file-system\" : \"memory\",\n\t\tmanager: (registryConfig, runConfig) =>\n\t\t\tnew FileSystemManagerDriver(\n\t\t\t\tregistryConfig,\n\t\t\t\trunConfig,\n\t\t\t\tstate,\n\t\t\t\tdriverConfig,\n\t\t\t),\n\t\tactor: (registryConfig, runConfig, managerDriver, inlineClient) => {\n\t\t\tconst actorDriver = new FileSystemActorDriver(\n\t\t\t\tregistryConfig,\n\t\t\t\trunConfig,\n\t\t\t\tmanagerDriver,\n\t\t\t\tinlineClient,\n\t\t\t\tstate,\n\t\t\t);\n\n\t\t\tstate.onRunnerStart(\n\t\t\t\tregistryConfig,\n\t\t\t\trunConfig,\n\t\t\t\tinlineClient,\n\t\t\t\tactorDriver,\n\t\t\t);\n\n\t\t\treturn actorDriver;\n\t\t},\n\t};\n\treturn driverConfig;\n}\n\nexport function createFileSystemDriver(opts?: { path?: string }): DriverConfig {\n\treturn createFileSystemOrMemoryDriver(true, opts?.path);\n}\n\nexport function createMemoryDriver(): DriverConfig {\n\treturn createFileSystemOrMemoryDriver(false);\n}\n","import invariant from \"invariant\";\nimport { type Client, createClientWithDriver } from \"@/client/client\";\nimport type { ClientConfig } from \"@/client/config\";\nimport { configureBaseLogger, configureDefaultLogger } from \"@/common/log\";\nimport type { ActorDriver } from \"@/driver-helpers/mod\";\nimport { chooseDefaultDriver } from \"@/drivers/default\";\nimport { ENGINE_ENDPOINT, ensureEngineProcess } from \"@/engine-process/mod\";\nimport {\n\tconfigureInspectorAccessToken,\n\tgetInspectorUrl,\n\tisInspectorEnabled,\n} from \"@/inspector/utils\";\nimport { createManagerRouter } from \"@/manager/router\";\nimport {\n\tgetDatacenters,\n\ttype RunnerConfigRequest,\n\tupdateRunnerConfig,\n} from \"@/remote-manager-driver/api-endpoints\";\nimport { getEndpoint } from \"@/remote-manager-driver/api-utils\";\nimport pkg from \"../../package.json\" with { type: \"json\" };\nimport {\n\ttype RegistryActors,\n\ttype RegistryConfig,\n\ttype RegistryConfigInput,\n\tRegistryConfigSchema,\n} from \"./config\";\nimport { logger } from \"./log\";\nimport {\n\ttype DriverConfig,\n\ttype RunnerConfig,\n\ttype RunnerConfigInput,\n\tRunnerConfigSchema,\n} from \"./run-config\";\nimport { crossPlatformServe } from \"./serve\";\n\nexport type ServerlessActorDriverBuilder = (\n\tupdateConfig: (config: RunnerConfig) => void,\n) => ActorDriver;\n\ninterface ServerOutput<A extends Registry<any>> {\n\t/** Client to communicate with the actors. */\n\tclient: Client<A>;\n\t/** Fetch handler to manually route requests to the Rivet manager API. */\n\tfetch: (request: Request, ...args: any) => Response | Promise<Response>;\n}\n\nexport class Registry<A extends RegistryActors> {\n\t#config: RegistryConfig;\n\n\tpublic get config(): RegistryConfig {\n\t\treturn this.#config;\n\t}\n\n\tconstructor(config: RegistryConfig) {\n\t\tthis.#config = config;\n\t}\n\n\t/**\n\t * Runs the registry for a server.\n\t */\n\tpublic start(inputConfig?: RunnerConfigInput): ServerOutput<this> {\n\t\tconst config = RunnerConfigSchema.parse(inputConfig);\n\n\t\t// Validate autoConfigureServerless is only used with serverless runner\n\t\tif (\n\t\t\tconfig.autoConfigureServerless &&\n\t\t\tconfig.runnerKind !== \"serverless\"\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t\"autoConfigureServerless can only be configured when runnerKind is 'serverless'\",\n\t\t\t);\n\t\t}\n\n\t\t// Promise for any async operations we need to wait to complete\n\t\tconst readyPromises: Promise<unknown>[] = [];\n\n\t\t// Disable health check if using serverless\n\t\t//\n\t\t// This is because the endpoint will not be configured until we receive\n\t\t// a serverless runner request, so we do not know what to health check\n\t\tif (config.runnerKind === \"serverless\") {\n\t\t\tlogger().debug(\"disabling health check since using serverless\");\n\t\t\tconfig.disableMetadataLookup = true;\n\t\t}\n\n\t\t// Auto-configure serverless runner if not in prod\n\t\tif (\n\t\t\tprocess.env.NODE_ENV !== \"production\" &&\n\t\t\tconfig.runnerKind === \"serverless\"\n\t\t) {\n\t\t\tif (inputConfig?.runEngine === undefined) config.runEngine = true;\n\t\t\tif (inputConfig?.autoConfigureServerless === undefined)\n\t\t\t\tconfig.autoConfigureServerless = true;\n\t\t}\n\n\t\t// Start engine\n\t\tif (config.runEngine) {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"run engine requested\",\n\t\t\t\tversion: config.runEngineVersion,\n\t\t\t});\n\n\t\t\t// Set config to point to the engine\n\t\t\tinvariant(\n\t\t\t\tconfig.endpoint === undefined,\n\t\t\t\t\"cannot specify 'endpoint' with 'runEngine'\",\n\t\t\t);\n\t\t\tconfig.endpoint = ENGINE_ENDPOINT;\n\t\t\tconfig.disableActorDriver = true;\n\n\t\t\t// Start the engine\n\t\t\tconst engineProcessPromise = ensureEngineProcess({\n\t\t\t\tversion: config.runEngineVersion,\n\t\t\t});\n\n\t\t\t// Chain ready promise\n\t\t\treadyPromises.push(engineProcessPromise);\n\t\t}\n\n\t\t// Configure for serverless\n\t\tif (config.runnerKind === \"serverless\") {\n\t\t\tconfig.defaultServerPort = 8080;\n\t\t\tconfig.overrideServerAddress = config.endpoint;\n\t\t\tconfig.disableActorDriver = true;\n\t\t}\n\n\t\t// Configure logger\n\t\tif (config.logging?.baseLogger) {\n\t\t\t// Use provided base logger\n\t\t\tconfigureBaseLogger(config.logging.baseLogger);\n\t\t} else {\n\t\t\t// Configure default logger with log level from config\n\t\t\t// getPinoLevel will handle env variable priority\n\t\t\tconfigureDefaultLogger(config.logging?.level);\n\t\t}\n\n\t\t// Choose the driver based on configuration\n\t\tconst driver = chooseDefaultDriver(config);\n\n\t\t// Set defaults based on the driver\n\t\tif (driver.name === \"engine\") {\n\t\t\tconfig.inspector.enabled = { manager: false, actor: true };\n\n\t\t\t// We need to leave the default server enabled for dev\n\t\t\tif (config.runnerKind !== \"serverless\") {\n\t\t\t\tconfig.disableDefaultServer = true;\n\t\t\t}\n\t\t}\n\t\tif (driver.name === \"cloudflare-workers\") {\n\t\t\tconfig.inspector.enabled = { manager: false, actor: true };\n\t\t\tconfig.disableDefaultServer = true;\n\t\t\tconfig.disableActorDriver = true;\n\t\t\tconfig.noWelcome = true;\n\t\t}\n\n\t\t// Configure getUpgradeWebSocket lazily so we can assign it in crossPlatformServe\n\t\tlet upgradeWebSocket: any;\n\t\tif (!config.getUpgradeWebSocket) {\n\t\t\tconfig.getUpgradeWebSocket = () => upgradeWebSocket!;\n\t\t}\n\n\t\t// Create router\n\t\tconst managerDriver = driver.manager(this.#config, config);\n\t\tconfigureInspectorAccessToken(config, managerDriver);\n\n\t\t// Create client\n\t\tconst client = createClientWithDriver<this>(managerDriver, config);\n\n\t\tconst driverLog = managerDriver.extraStartupLog?.() ?? {};\n\t\tlogger().info({\n\t\t\tmsg: \"rivetkit ready\",\n\t\t\tdriver: driver.name,\n\t\t\tdefinitions: Object.keys(this.#config.use).length,\n\t\t\t...driverLog,\n\t\t});\n\t\tif (isInspectorEnabled(config, \"manager\") && managerDriver.inspector) {\n\t\t\tlogger().info({\n\t\t\t\tmsg: \"inspector ready\",\n\t\t\t\turl: getInspectorUrl(config),\n\t\t\t});\n\t\t}\n\n\t\t// Print welcome information\n\t\tif (!config.noWelcome) {\n\t\t\tconst displayInfo = managerDriver.displayInformation();\n\t\t\tconsole.log();\n\t\t\tconsole.log(` RivetKit ${pkg.version} (${displayInfo.name})`);\n\t\t\tif (!config.disableDefaultServer) {\n\t\t\t\tconsole.log(` - Endpoint: ${getEndpoint(config)}`);\n\t\t\t} else if (config.overrideServerAddress) {\n\t\t\t\tconsole.log(\n\t\t\t\t\t` - Endpoint: ${config.overrideServerAddress}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (config.runEngine) {\n\t\t\t\tconst padding = \" \".repeat(Math.max(0, 13 - \"Engine\".length));\n\t\t\t\tconsole.log(` - Engine:${padding}v${config.runEngineVersion}`);\n\t\t\t}\n\t\t\tfor (const [k, v] of Object.entries(displayInfo.properties)) {\n\t\t\t\tconst padding = \" \".repeat(Math.max(0, 13 - k.length));\n\t\t\t\tconsole.log(` - ${k}:${padding}${v}`);\n\t\t\t}\n\t\t\tif (\n\t\t\t\tisInspectorEnabled(config, \"manager\") &&\n\t\t\t\tmanagerDriver.inspector\n\t\t\t) {\n\t\t\t\tconsole.log(` - Inspector: ${getInspectorUrl(config)}`);\n\t\t\t}\n\t\t\tconsole.log();\n\t\t}\n\n\t\tconst { router: hono } = createManagerRouter(\n\t\t\tthis.#config,\n\t\t\tconfig,\n\t\t\tmanagerDriver,\n\t\t\tdriver,\n\t\t\tclient,\n\t\t);\n\n\t\t// Start server\n\t\tif (!config.disableDefaultServer) {\n\t\t\tconst serverPromise = (async () => {\n\t\t\t\tconst out = await crossPlatformServe(config, hono);\n\t\t\t\tupgradeWebSocket = out.upgradeWebSocket;\n\t\t\t})();\n\t\t\treadyPromises.push(serverPromise);\n\t\t}\n\n\t\t// HACK: We need to find a better way to let the driver itself decide when to start the actor driver\n\t\t// Create runner\n\t\t//\n\t\t// Even though we do not use the returned ActorDriver, this is required to start the code that will handle incoming actors\n\t\tif (!config.disableActorDriver) {\n\t\t\tPromise.all(readyPromises).then(async () => {\n\t\t\t\tlogger().debug(\"starting actor driver\");\n\t\t\t\tdriver.actor(this.#config, config, managerDriver, client);\n\t\t\t});\n\t\t}\n\n\t\t// Configure serverless runner if enabled when actor driver is disabled\n\t\tif (\n\t\t\tconfig.runnerKind === \"serverless\" &&\n\t\t\tconfig.autoConfigureServerless\n\t\t) {\n\t\t\tPromise.all(readyPromises).then(async () => {\n\t\t\t\tawait configureServerlessRunner(config);\n\t\t\t});\n\t\t}\n\n\t\treturn {\n\t\t\tclient,\n\t\t\tfetch: hono.fetch.bind(hono),\n\t\t};\n\t}\n}\n\nasync function configureServerlessRunner(config: RunnerConfig): Promise<void> {\n\tlogger().debug(\"configuring serverless runner\");\n\n\ttry {\n\t\t// Ensure we have required config values\n\t\tif (!config.runnerName) {\n\t\t\tthrow new Error(\n\t\t\t\t\"runnerName is required for serverless configuration\",\n\t\t\t);\n\t\t}\n\t\tif (!config.namespace) {\n\t\t\tthrow new Error(\n\t\t\t\t\"namespace is required for serverless configuration\",\n\t\t\t);\n\t\t}\n\t\tif (!config.endpoint) {\n\t\t\tthrow new Error(\n\t\t\t\t\"endpoint is required for serverless configuration\",\n\t\t\t);\n\t\t}\n\n\t\t// Prepare the configuration\n\t\tconst customConfig =\n\t\t\ttypeof config.autoConfigureServerless === \"object\"\n\t\t\t\t? config.autoConfigureServerless\n\t\t\t\t: {};\n\n\t\t// Create a ClientConfig from RunnerConfig for API calls\n\t\tconst clientConfig: ClientConfig = {\n\t\t\tendpoint: config.endpoint,\n\t\t\ttoken: config.token,\n\t\t\tnamespace: config.namespace,\n\t\t\trunnerName: config.runnerName,\n\t\t\tencoding: config.encoding,\n\t\t\theaders: config.headers,\n\t\t\tgetUpgradeWebSocket: config.getUpgradeWebSocket,\n\t\t\tdisableMetadataLookup: true, // We don't need health check for this operation\n\t\t};\n\n\t\t// Fetch all datacenters\n\t\tlogger().debug({\n\t\t\tmsg: \"fetching datacenters\",\n\t\t\tendpoint: config.endpoint,\n\t\t});\n\t\tconst dcsRes = await getDatacenters(clientConfig);\n\n\t\t// Build the request body\n\t\tlogger().debug({\n\t\t\tmsg: \"configuring serverless runner\",\n\t\t\trunnerName: config.runnerName,\n\t\t\tnamespace: config.namespace,\n\t\t});\n\t\tconst serverlessConfig = {\n\t\t\tserverless: {\n\t\t\t\turl:\n\t\t\t\t\tcustomConfig.url ||\n\t\t\t\t\t`http://localhost:${config.defaultServerPort}`,\n\t\t\t\theaders: customConfig.headers || {},\n\t\t\t\tmax_runners: customConfig.maxRunners ?? 100,\n\t\t\t\tmin_runners: customConfig.minRunners ?? 0,\n\t\t\t\trequest_lifespan: customConfig.requestLifespan ?? 15 * 60,\n\t\t\t\trunners_margin: customConfig.runnersMargin ?? 0,\n\t\t\t\tslots_per_runner:\n\t\t\t\t\tcustomConfig.slotsPerRunner ?? config.totalSlots ?? 1000,\n\t\t\t},\n\t\t\tmetadata: customConfig.metadata ?? {},\n\t\t};\n\t\tawait updateRunnerConfig(clientConfig, config.runnerName, {\n\t\t\tdatacenters: Object.fromEntries(\n\t\t\t\tdcsRes.datacenters.map((dc) => [dc.name, serverlessConfig]),\n\t\t\t),\n\t\t});\n\n\t\tlogger().info({\n\t\t\tmsg: \"serverless runner configured successfully\",\n\t\t\trunnerName: config.runnerName,\n\t\t\tnamespace: config.namespace,\n\t\t});\n\t} catch (error) {\n\t\tlogger().error({\n\t\t\tmsg: \"failed to configure serverless runner, validate endpoint is configured correctly then restart this process\",\n\t\t\terror,\n\t\t});\n\n\t\t// Don't throw, allow the runner to continue\n\t}\n}\n\nexport function setup<A extends RegistryActors>(\n\tinput: RegistryConfigInput<A>,\n): Registry<A> {\n\tconst config = RegistryConfigSchema.parse(input);\n\treturn new Registry(config);\n}\n\nexport type {\n\tRegistryConfig,\n\tRegistryActors,\n\tRunnerConfig as RunConfig,\n\tRunnerConfigInput as RunConfigInput,\n\tDriverConfig,\n};\nexport { RegistryConfigSchema };\n","import { UserError } from \"@/actor/errors\";\nimport { loggerWithoutContext } from \"@/actor/log\";\nimport { createEngineDriver } from \"@/drivers/engine/mod\";\nimport { createFileSystemOrMemoryDriver } from \"@/drivers/file-system/mod\";\nimport type { DriverConfig, RunnerConfig } from \"@/registry/run-config\";\n\n/**\n * Chooses the appropriate driver based on the run configuration.\n */\nexport function chooseDefaultDriver(runConfig: RunnerConfig): DriverConfig {\n\tif (runConfig.endpoint && runConfig.driver) {\n\t\tthrow new UserError(\n\t\t\t\"Cannot specify both 'endpoint' and 'driver' in configuration\",\n\t\t);\n\t}\n\n\tif (runConfig.driver) {\n\t\treturn runConfig.driver;\n\t}\n\n\tif (\n\t\trunConfig.endpoint ||\n\t\trunConfig.token ||\n\t\trunConfig.runnerKind === \"serverless\"\n\t) {\n\t\tloggerWithoutContext().debug({\n\t\t\tmsg: \"using rivet engine driver\",\n\t\t\tendpoint: runConfig.endpoint,\n\t\t});\n\t\treturn createEngineDriver();\n\t}\n\n\tloggerWithoutContext().debug({ msg: \"using default file system driver\" });\n\treturn createFileSystemOrMemoryDriver(true);\n}\n","import { getLogger } from \"@/common/log\";\n\nexport function logger() {\n\treturn getLogger(\"engine-process\");\n}\n","import {\n\tensureDirectoryExists,\n\tgetStoragePath,\n} from \"@/drivers/file-system/utils\";\nimport {\n\tgetNodeChildProcess,\n\tgetNodeCrypto,\n\tgetNodeFs,\n\tgetNodeFsSync,\n\tgetNodePath,\n\tgetNodeStream,\n\timportNodeDependencies,\n} from \"@/utils/node\";\nimport { logger } from \"./log\";\n\nexport const ENGINE_PORT = 6420;\nexport const ENGINE_ENDPOINT = `http://localhost:${ENGINE_PORT}`;\n\nconst ENGINE_BASE_URL = \"https://releases.rivet.gg/engine\";\nconst ENGINE_BINARY_NAME = \"rivet-engine\";\n\ninterface EnsureEngineProcessOptions {\n\tversion: string;\n}\n\nexport async function ensureEngineProcess(\n\toptions: EnsureEngineProcessOptions,\n): Promise<void> {\n\timportNodeDependencies();\n\n\tlogger().debug({\n\t\tmsg: \"ensuring engine process\",\n\t\tversion: options.version,\n\t});\n\n\tconst path = getNodePath();\n\tconst storageRoot = getStoragePath();\n\tconst binDir = path.join(storageRoot, \"bin\");\n\tconst varDir = path.join(storageRoot, \"var\");\n\tconst logsDir = path.join(varDir, \"logs\", \"rivet-engine\");\n\tawait ensureDirectoryExists(binDir);\n\tawait ensureDirectoryExists(varDir);\n\tawait ensureDirectoryExists(logsDir);\n\n\tconst executableName =\n\t\tprocess.platform === \"win32\"\n\t\t\t? `${ENGINE_BINARY_NAME}-${options.version}.exe`\n\t\t\t: `${ENGINE_BINARY_NAME}-${options.version}`;\n\tconst binaryPath = path.join(binDir, executableName);\n\tawait downloadEngineBinaryIfNeeded(binaryPath, options.version, varDir);\n\n\t// Check if the engine is already running on the port\n\tif (await isEngineRunning()) {\n\t\ttry {\n\t\t\tawait waitForEngineHealth();\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"engine already running and healthy\",\n\t\t\t\tversion: options.version,\n\t\t\t});\n\t\t\treturn;\n\t\t} catch (error) {\n\t\t\tlogger().warn({\n\t\t\t\tmsg: \"existing engine process not healthy, cannot restart automatically\",\n\t\t\t\terror,\n\t\t\t});\n\t\t\tthrow new Error(\n\t\t\t\t\"Engine process exists but is not healthy. Please manually stop the process on port 6420 and retry.\",\n\t\t\t);\n\t\t}\n\t}\n\t// Create log file streams with timestamp in the filename\n\tconst timestamp = new Date()\n\t\t.toISOString()\n\t\t.replace(/:/g, \"-\")\n\t\t.replace(/\\./g, \"-\");\n\tconst stdoutLogPath = path.join(logsDir, `engine-${timestamp}-stdout.log`);\n\tconst stderrLogPath = path.join(logsDir, `engine-${timestamp}-stderr.log`);\n\n\tconst fsSync = getNodeFsSync();\n\tconst stdoutStream = fsSync.createWriteStream(stdoutLogPath, {\n\t\tflags: \"a\",\n\t});\n\tconst stderrStream = fsSync.createWriteStream(stderrLogPath, {\n\t\tflags: \"a\",\n\t});\n\n\tlogger().debug({\n\t\tmsg: \"creating engine log files\",\n\t\tstdout: stdoutLogPath,\n\t\tstderr: stderrLogPath,\n\t});\n\n\tconst childProcess = getNodeChildProcess();\n\tconst child = childProcess.spawn(binaryPath, [\"start\"], {\n\t\tcwd: path.dirname(binaryPath),\n\t\tstdio: [\"inherit\", \"pipe\", \"pipe\"],\n\t\tenv: {\n\t\t\t...process.env,\n\t\t},\n\t});\n\n\tif (!child.pid) {\n\t\tthrow new Error(\"failed to spawn rivet engine process\");\n\t}\n\n\t// Pipe stdout and stderr to log files\n\tif (child.stdout) {\n\t\tchild.stdout.pipe(stdoutStream);\n\t}\n\tif (child.stderr) {\n\t\tchild.stderr.pipe(stderrStream);\n\t}\n\tlogger().debug({\n\t\tmsg: \"spawned engine process\",\n\t\tpid: child.pid,\n\t\tcwd: path.dirname(binaryPath),\n\t});\n\n\tchild.once(\"exit\", (code, signal) => {\n\t\tlogger().warn({\n\t\t\tmsg: \"engine process exited, please report this error\",\n\t\t\tcode,\n\t\t\tsignal,\n\t\t\tissues: \"https://github.com/rivet-dev/rivetkit/issues\",\n\t\t\tsupport: \"https://rivet.dev/discord\",\n\t\t});\n\t\t// Clean up log streams\n\t\tstdoutStream.end();\n\t\tstderrStream.end();\n\t});\n\n\tchild.once(\"error\", (error) => {\n\t\tlogger().error({\n\t\t\tmsg: \"engine process failed\",\n\t\t\terror,\n\t\t});\n\t\t// Clean up log streams on error\n\t\tstdoutStream.end();\n\t\tstderrStream.end();\n\t});\n\n\t// Wait for engine to be ready\n\tawait waitForEngineHealth();\n\n\tlogger().info({\n\t\tmsg: \"engine process started\",\n\t\tpid: child.pid,\n\t\tversion: options.version,\n\t\tlogs: {\n\t\t\tstdout: stdoutLogPath,\n\t\t\tstderr: stderrLogPath,\n\t\t},\n\t});\n}\n\nasync function downloadEngineBinaryIfNeeded(\n\tbinaryPath: string,\n\tversion: string,\n\tvarDir: string,\n): Promise<void> {\n\tconst binaryExists = await fileExists(binaryPath);\n\tif (binaryExists) {\n\t\tlogger().debug({\n\t\t\tmsg: \"engine binary already cached\",\n\t\t\tversion,\n\t\t\tpath: binaryPath,\n\t\t});\n\t\treturn;\n\t}\n\n\tconst { targetTriplet, extension } = resolveTargetTriplet();\n\tconst remoteFile = `${ENGINE_BINARY_NAME}-${targetTriplet}${extension}`;\n\tconst downloadUrl = `${ENGINE_BASE_URL}/${version}/${remoteFile}`;\n\tlogger().info({\n\t\tmsg: \"downloading engine binary\",\n\t\turl: downloadUrl,\n\t\tpath: binaryPath,\n\t\tversion,\n\t});\n\n\tconst response = await fetch(downloadUrl);\n\tif (!response.ok || !response.body) {\n\t\tthrow new Error(\n\t\t\t`failed to download rivet engine binary from ${downloadUrl}: ${response.status} ${response.statusText}`,\n\t\t);\n\t}\n\n\t// Generate unique temp file name to prevent parallel download conflicts\n\tconst crypto = getNodeCrypto();\n\tconst tempPath = `${binaryPath}.${crypto.randomUUID()}.tmp`;\n\tconst startTime = Date.now();\n\n\tlogger().debug({\n\t\tmsg: \"starting binary download\",\n\t\ttempPath,\n\t\tcontentLength: response.headers.get(\"content-length\"),\n\t});\n\n\t// Warn user if download is taking a long time\n\tconst slowDownloadWarning = setTimeout(() => {\n\t\tlogger().warn({\n\t\t\tmsg: \"engine binary download is taking longer than expected, please be patient\",\n\t\t\tversion,\n\t\t});\n\t}, 5000);\n\n\ttry {\n\t\tconst stream = getNodeStream();\n\t\tconst fsSync = getNodeFsSync();\n\t\tawait stream.pipeline(\n\t\t\tresponse.body,\n\t\t\tfsSync.createWriteStream(tempPath),\n\t\t);\n\n\t\t// Clear the slow download warning\n\t\tclearTimeout(slowDownloadWarning);\n\n\t\t// Get file size to verify download\n\t\tconst fs = getNodeFs();\n\t\tconst stats = await fs.stat(tempPath);\n\t\tconst downloadDuration = Date.now() - startTime;\n\n\t\tif (process.platform !== \"win32\") {\n\t\t\tawait fs.chmod(tempPath, 0o755);\n\t\t}\n\t\tawait fs.rename(tempPath, binaryPath);\n\n\t\tlogger().debug({\n\t\t\tmsg: \"engine binary download complete\",\n\t\t\tversion,\n\t\t\tpath: binaryPath,\n\t\t\tsize: stats.size,\n\t\t\tdurationMs: downloadDuration,\n\t\t});\n\t\tlogger().info({\n\t\t\tmsg: \"engine binary downloaded\",\n\t\t\tversion,\n\t\t\tpath: binaryPath,\n\t\t});\n\t} catch (error) {\n\t\t// Clear the slow download warning\n\t\tclearTimeout(slowDownloadWarning);\n\n\t\t// Clean up partial temp file on error\n\t\tlogger().warn({\n\t\t\tmsg: \"engine download failed, please report this error\",\n\t\t\ttempPath,\n\t\t\terror,\n\t\t\tissues: \"https://github.com/rivet-dev/rivetkit/issues\",\n\t\t\tsupport: \"https://rivet.dev/discord\",\n\t\t});\n\t\ttry {\n\t\t\tconst fs = getNodeFs();\n\t\t\tawait fs.unlink(tempPath);\n\t\t} catch (unlinkError) {\n\t\t\t// Ignore errors when cleaning up (file may not exist)\n\t\t}\n\t\tthrow error;\n\t}\n}\n//\nfunction resolveTargetTriplet(): { targetTriplet: string; extension: string } {\n\treturn resolveTargetTripletFor(process.platform, process.arch);\n}\n\nexport function resolveTargetTripletFor(\n\tplatform: NodeJS.Platform,\n\tarch: typeof process.arch,\n): { targetTriplet: string; extension: string } {\n\tswitch (platform) {\n\t\tcase \"darwin\":\n\t\t\tif (arch === \"arm64\") {\n\t\t\t\treturn { targetTriplet: \"aarch64-apple-darwin\", extension: \"\" };\n\t\t\t}\n\t\t\tif (arch === \"x64\") {\n\t\t\t\treturn { targetTriplet: \"x86_64-apple-darwin\", extension: \"\" };\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"linux\":\n\t\t\tif (arch === \"x64\") {\n\t\t\t\treturn {\n\t\t\t\t\ttargetTriplet: \"x86_64-unknown-linux-musl\",\n\t\t\t\t\textension: \"\",\n\t\t\t\t};\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"win32\":\n\t\t\tif (arch === \"x64\") {\n\t\t\t\treturn {\n\t\t\t\t\ttargetTriplet: \"x86_64-pc-windows-gnu\",\n\t\t\t\t\textension: \".exe\",\n\t\t\t\t};\n\t\t\t}\n\t\t\tbreak;\n\t}\n\n\tthrow new Error(\n\t\t`unsupported platform for rivet engine binary: ${platform}/${arch}`,\n\t);\n}\nasync function isEngineRunning(): Promise<boolean> {\n\t// Check if the engine is running on the port\n\treturn await checkIfEngineAlreadyRunningOnPort(ENGINE_PORT);\n}\n\nasync function checkIfEngineAlreadyRunningOnPort(\n\tport: number,\n): Promise<boolean> {\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(`http://localhost:${port}/health`);\n\t} catch (err) {\n\t\t// Nothing is running on this port\n\t\treturn false;\n\t}\n\n\tif (response.ok) {\n\t\tconst health = (await response.json()) as {\n\t\t\tstatus?: string;\n\t\t\truntime?: string;\n\t\t\tversion?: string;\n\t\t};\n\n\t\t// Check what's running on this port\n\t\tif (health.runtime === \"engine\") {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"rivet engine already running on port\",\n\t\t\t\tport,\n\t\t\t});\n\t\t\treturn true;\n\t\t} else if (health.runtime === \"rivetkit\") {\n\t\t\tlogger().error({\n\t\t\t\tmsg: \"another rivetkit process is already running on port\",\n\t\t\t\tport,\n\t\t\t});\n\t\t\tthrow new Error(\n\t\t\t\t\"RivetKit process already running on port 6420, stop that process and restart this.\",\n\t\t\t);\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t\"Unknown process running on port 6420, cannot identify what it is.\",\n\t\t\t);\n\t\t}\n\t}\n\n\t// Port responded but not with OK status\n\treturn false;\n}\nasync function fileExists(filePath: string): Promise<boolean> {\n\ttry {\n\t\tconst fs = getNodeFs();\n\t\tawait fs.access(filePath);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nconst HEALTH_MAX_WAIT = 10_000;\nconst HEALTH_INTERVAL = 100;\n\nasync function waitForEngineHealth(): Promise<void> {\n\tconst maxRetries = Math.ceil(HEALTH_MAX_WAIT / HEALTH_INTERVAL);\n\n\tlogger().debug({ msg: \"waiting for engine health check\" });\n\n\tfor (let i = 0; i < maxRetries; i++) {\n\t\ttry {\n\t\t\tconst response = await fetch(`${ENGINE_ENDPOINT}/health`);\n\t\t\tif (response.ok) {\n\t\t\t\tlogger().debug({ msg: \"engine health check passed\" });\n\t\t\t\treturn;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Expected to fail while engine is starting up\n\t\t\tif (i === maxRetries - 1) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`engine health check failed after ${maxRetries} retries: ${error}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (i < maxRetries - 1) {\n\t\t\tlogger().trace({\n\t\t\t\tmsg: \"engine not ready, retrying\",\n\t\t\t\tattempt: i + 1,\n\t\t\t\tmaxRetries,\n\t\t\t});\n\t\t\tawait new Promise((resolve) =>\n\t\t\t\tsetTimeout(resolve, HEALTH_INTERVAL),\n\t\t\t);\n\t\t}\n\t}\n\n\tthrow new Error(`engine health check failed after ${maxRetries} retries`);\n}\n","import { createRoute, OpenAPIHono } from \"@hono/zod-openapi\";\nimport * as cbor from \"cbor-x\";\nimport {\n\tHono,\n\ttype Context as HonoContext,\n\ttype MiddlewareHandler,\n\ttype Next,\n} from \"hono\";\nimport { createMiddleware } from \"hono/factory\";\nimport invariant from \"invariant\";\nimport { z } from \"zod\";\nimport { ActorNotFound, InvalidRequest, Unsupported } from \"@/actor/errors\";\nimport { serializeActorKey } from \"@/actor/keys\";\nimport type { Client, Encoding } from \"@/client/mod\";\nimport {\n\tWS_PROTOCOL_ACTOR,\n\tWS_PROTOCOL_CONN_PARAMS,\n\tWS_PROTOCOL_ENCODING,\n\tWS_TEST_PROTOCOL_PATH,\n} from \"@/common/actor-router-consts\";\nimport { cors } from \"@/common/cors\";\nimport {\n\thandleHealthRequest,\n\thandleMetadataRequest,\n\thandleRouteError,\n\thandleRouteNotFound,\n\tloggerMiddleware,\n} from \"@/common/router\";\nimport {\n\tassertUnreachable,\n\tdeconstructError,\n\tnoopNext,\n\tstringifyError,\n} from \"@/common/utils\";\nimport { HEADER_ACTOR_ID } from \"@/driver-helpers/mod\";\nimport type {\n\tTestInlineDriverCallRequest,\n\tTestInlineDriverCallResponse,\n} from \"@/driver-test-suite/test-inline-client-driver\";\nimport { createManagerInspectorRouter } from \"@/inspector/manager\";\nimport { isInspectorEnabled, secureInspector } from \"@/inspector/utils\";\nimport {\n\tActorsCreateRequestSchema,\n\ttype ActorsCreateResponse,\n\tActorsCreateResponseSchema,\n\tActorsGetOrCreateRequestSchema,\n\ttype ActorsGetOrCreateResponse,\n\tActorsGetOrCreateResponseSchema,\n\ttype ActorsListNamesResponse,\n\tActorsListNamesResponseSchema,\n\ttype ActorsListResponse,\n\tActorsListResponseSchema,\n\ttype Actor as ApiActor,\n} from \"@/manager-api/actors\";\nimport type { AnyClient } from \"@/mod\";\nimport { buildActorNames, type RegistryConfig } from \"@/registry/config\";\nimport type { DriverConfig, RunnerConfig } from \"@/registry/run-config\";\nimport type { ActorOutput, ManagerDriver } from \"./driver\";\nimport { actorGateway, createTestWebSocketProxy } from \"./gateway\";\nimport { logger } from \"./log\";\nimport { ServerlessStartHeadersSchema } from \"./router-schema\";\n\nfunction buildOpenApiResponses<T>(schema: T) {\n\treturn {\n\t\t200: {\n\t\t\tdescription: \"Success\",\n\t\t\tcontent: {\n\t\t\t\t\"application/json\": {\n\t\t\t\t\tschema,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t400: {\n\t\t\tdescription: \"User error\",\n\t\t},\n\t\t500: {\n\t\t\tdescription: \"Internal error\",\n\t\t},\n\t};\n}\n\nfunction buildOpenApiRequestBody<T>(schema: T) {\n\treturn {\n\t\trequired: true,\n\t\tcontent: {\n\t\t\t\"application/json\": {\n\t\t\t\tschema,\n\t\t\t},\n\t\t},\n\t};\n}\n\nexport function createManagerRouter(\n\tregistryConfig: RegistryConfig,\n\trunConfig: RunnerConfig,\n\tmanagerDriver: ManagerDriver,\n\tdriverConfig: DriverConfig,\n\tclient: AnyClient,\n): { router: Hono; openapi: OpenAPIHono } {\n\tconst router = new OpenAPIHono({ strict: false }).basePath(\n\t\trunConfig.basePath,\n\t);\n\n\trouter.use(\"*\", loggerMiddleware(logger()), cors());\n\n\t// HACK: Add Sec-WebSocket-Protocol header to fix KIT-339\n\t//\n\t// Some Deno WebSocket providers do not auto-set the protocol, which\n\t// will cause some WebSocket clients to fail\n\trouter.use(\n\t\t\"*\",\n\t\tcreateMiddleware(async (c, next) => {\n\t\t\tconst upgrade = c.req.header(\"upgrade\");\n\t\t\tconst isWebSocket = upgrade?.toLowerCase() === \"websocket\";\n\t\t\tconst isGet = c.req.method === \"GET\";\n\n\t\t\tif (isGet && isWebSocket) {\n\t\t\t\tc.header(\"Sec-WebSocket-Protocol\", \"rivet\");\n\t\t\t}\n\n\t\t\tawait next();\n\t\t}),\n\t);\n\n\tif (runConfig.runnerKind === \"serverless\") {\n\t\taddServerlessRoutes(\n\t\t\tdriverConfig,\n\t\t\tregistryConfig,\n\t\t\trunConfig,\n\t\t\tmanagerDriver,\n\t\t\tclient,\n\t\t\trouter,\n\t\t);\n\t} else if (runConfig.runnerKind === \"normal\") {\n\t\taddManagerRoutes(registryConfig, runConfig, managerDriver, router);\n\t} else {\n\t\tassertUnreachable(runConfig.runnerKind);\n\t}\n\n\t// Error handling\n\trouter.notFound(handleRouteNotFound);\n\trouter.onError(handleRouteError);\n\n\treturn { router: router as Hono, openapi: router };\n}\n\nfunction addServerlessRoutes(\n\tdriverConfig: DriverConfig,\n\tregistryConfig: RegistryConfig,\n\trunConfig: RunnerConfig,\n\tmanagerDriver: ManagerDriver,\n\tclient: AnyClient,\n\trouter: OpenAPIHono,\n) {\n\t// GET /\n\trouter.get(\"/\", (c) => {\n\t\treturn c.text(\n\t\t\t\"This is a RivetKit server.\\n\\nLearn more at https://rivetkit.org\",\n\t\t);\n\t});\n\n\t// Serverless start endpoint\n\trouter.get(\"/start\", async (c) => {\n\t\t// Parse headers\n\t\tconst parseResult = ServerlessStartHeadersSchema.safeParse({\n\t\t\tendpoint: c.req.header(\"x-rivet-endpoint\"),\n\t\t\ttoken: c.req.header(\"x-rivet-token\") ?? undefined,\n\t\t\ttotalSlots: c.req.header(\"x-rivet-total-slots\"),\n\t\t\trunnerName: c.req.header(\"x-rivet-runner-name\"),\n\t\t\tnamespace: c.req.header(\"x-rivet-namespace-name\"),\n\t\t});\n\t\tif (!parseResult.success) {\n\t\t\tthrow new InvalidRequest(\n\t\t\t\tparseResult.error.issues[0]?.message ??\n\t\t\t\t\t\"invalid serverless start headers\",\n\t\t\t);\n\t\t}\n\t\tconst { endpoint, token, totalSlots, runnerName, namespace } =\n\t\t\tparseResult.data;\n\n\t\tlogger().debug({\n\t\t\tmsg: \"received serverless runner start request\",\n\t\t\tendpoint,\n\t\t\ttotalSlots,\n\t\t\trunnerName,\n\t\t\tnamespace,\n\t\t});\n\n\t\t// Override config\n\t\t//\n\t\t// We can't do a structuredClone here since this holds functions\n\t\tconst newRunConfig = Object.assign({}, runConfig);\n\t\tnewRunConfig.endpoint = endpoint;\n\t\tnewRunConfig.token = token;\n\t\tnewRunConfig.totalSlots = totalSlots;\n\t\tnewRunConfig.runnerName = runnerName;\n\t\tnewRunConfig.namespace = namespace;\n\t\tif (newRunConfig.runnerKey) {\n\t\t\tlogger().warn({\n\t\t\t\tmsg: \"runner keys are not supported by serverless runners, this will be overwritten with a random runner key\",\n\t\t\t\toldRunnerKey: newRunConfig.runnerKey,\n\t\t\t});\n\t\t\tnewRunConfig.runnerKey = undefined;\n\t\t}\n\n\t\t// Create new actor driver with updated config\n\t\tconst actorDriver = driverConfig.actor(\n\t\t\tregistryConfig,\n\t\t\tnewRunConfig,\n\t\t\tmanagerDriver,\n\t\t\tclient,\n\t\t);\n\t\tinvariant(\n\t\t\tactorDriver.serverlessHandleStart,\n\t\t\t\"missing serverlessHandleStart on ActorDriver\",\n\t\t);\n\n\t\treturn await actorDriver.serverlessHandleStart(c);\n\t});\n\n\trouter.get(\"/health\", (c) => handleHealthRequest(c));\n\n\trouter.get(\"/metadata\", (c) =>\n\t\thandleMetadataRequest(c, registryConfig, runConfig),\n\t);\n}\n\nfunction addManagerRoutes(\n\tregistryConfig: RegistryConfig,\n\trunConfig: RunnerConfig,\n\tmanagerDriver: ManagerDriver,\n\trouter: OpenAPIHono,\n) {\n\t// TODO(kacper): Remove this in favor of standard manager API\n\t// Inspector\n\tif (isInspectorEnabled(runConfig, \"manager\")) {\n\t\tif (!managerDriver.inspector) {\n\t\t\tthrow new Unsupported(\"inspector\");\n\t\t}\n\t\trouter.route(\n\t\t\t\"/inspect\",\n\t\t\tnew Hono<{ Variables: { inspector: any } }>()\n\t\t\t\t.use(secureInspector(runConfig))\n\t\t\t\t.use((c, next) => {\n\t\t\t\t\tc.set(\"inspector\", managerDriver.inspector!);\n\t\t\t\t\treturn next();\n\t\t\t\t})\n\t\t\t\t.route(\"/\", createManagerInspectorRouter()),\n\t\t);\n\t}\n\n\t// Actor gateway\n\trouter.use(\"*\", actorGateway.bind(undefined, runConfig, managerDriver));\n\n\t// GET /\n\trouter.get(\"/\", (c) => {\n\t\treturn c.text(\n\t\t\t\"This is a RivetKit server.\\n\\nLearn more at https://rivetkit.org\",\n\t\t);\n\t});\n\n\t// GET /actors\n\t{\n\t\tconst route = createRoute({\n\t\t\tmethod: \"get\",\n\t\t\tpath: \"/actors\",\n\t\t\trequest: {\n\t\t\t\tquery: z.object({\n\t\t\t\t\tname: z.string().optional(),\n\t\t\t\t\tactor_ids: z.string().optional(),\n\t\t\t\t\tkey: z.string().optional(),\n\t\t\t\t}),\n\t\t\t},\n\t\t\tresponses: buildOpenApiResponses(ActorsListResponseSchema),\n\t\t});\n\n\t\trouter.openapi(route, async (c) => {\n\t\t\tconst { name, actor_ids, key } = c.req.valid(\"query\");\n\n\t\t\tconst actorIdsParsed = actor_ids\n\t\t\t\t? actor_ids\n\t\t\t\t\t\t.split(\",\")\n\t\t\t\t\t\t.map((id) => id.trim())\n\t\t\t\t\t\t.filter((id) => id.length > 0)\n\t\t\t\t: undefined;\n\n\t\t\tconst actors: ActorOutput[] = [];\n\n\t\t\t// Validate: cannot provide both actor_ids and (name or key)\n\t\t\tif (actorIdsParsed && (name || key)) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: \"Cannot provide both actor_ids and (name + key). Use either actor_ids or (name + key).\",\n\t\t\t\t\t},\n\t\t\t\t\t400,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Validate: when key is provided, name must also be provided\n\t\t\tif (key && !name) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: \"Name is required when key is provided.\",\n\t\t\t\t\t},\n\t\t\t\t\t400,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (actorIdsParsed) {\n\t\t\t\tif (actorIdsParsed.length > 32) {\n\t\t\t\t\treturn c.json(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\terror: `Too many actor IDs. Maximum is 32, got ${actorIdsParsed.length}.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t400,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (actorIdsParsed.length === 0) {\n\t\t\t\t\treturn c.json<ActorsListResponse>({\n\t\t\t\t\t\tactors: [],\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Fetch actors by ID\n\t\t\t\tfor (const actorId of actorIdsParsed) {\n\t\t\t\t\tif (name) {\n\t\t\t\t\t\t// If name is provided, use it directly\n\t\t\t\t\t\tconst actorOutput = await managerDriver.getForId({\n\t\t\t\t\t\t\tc,\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\tactorId,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (actorOutput) {\n\t\t\t\t\t\t\tactors.push(actorOutput);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If no name is provided, try all registered actor types\n\t\t\t\t\t\t// Actor IDs are globally unique, so we'll find it in one of them\n\t\t\t\t\t\tfor (const actorName of Object.keys(\n\t\t\t\t\t\t\tregistryConfig.use,\n\t\t\t\t\t\t)) {\n\t\t\t\t\t\t\tconst actorOutput = await managerDriver.getForId({\n\t\t\t\t\t\t\t\tc,\n\t\t\t\t\t\t\t\tname: actorName,\n\t\t\t\t\t\t\t\tactorId,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (actorOutput) {\n\t\t\t\t\t\t\t\tactors.push(actorOutput);\n\t\t\t\t\t\t\t\tbreak; // Found the actor, no need to check other names\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (key && name) {\n\t\t\t\tconst actorOutput = await managerDriver.getWithKey({\n\t\t\t\t\tc,\n\t\t\t\t\tname,\n\t\t\t\t\tkey: [key], // Convert string to ActorKey array\n\t\t\t\t});\n\t\t\t\tif (actorOutput) {\n\t\t\t\t\tactors.push(actorOutput);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (!name) {\n\t\t\t\t\treturn c.json(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\terror: \"Name is required when not using actor_ids.\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t400,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// List all actors with the given name\n\t\t\t\tconst actorOutputs = await managerDriver.listActors({\n\t\t\t\t\tc,\n\t\t\t\t\tname,\n\t\t\t\t\tkey,\n\t\t\t\t\tincludeDestroyed: false,\n\t\t\t\t});\n\t\t\t\tactors.push(...actorOutputs);\n\t\t\t}\n\n\t\t\treturn c.json<ActorsListResponse>({\n\t\t\t\tactors: actors.map((actor) =>\n\t\t\t\t\tcreateApiActor(actor, runConfig.runnerName),\n\t\t\t\t),\n\t\t\t});\n\t\t});\n\t}\n\n\t// GET /actors/names\n\t{\n\t\tconst route = createRoute({\n\t\t\tmethod: \"get\",\n\t\t\tpath: \"/actors/names\",\n\t\t\trequest: {\n\t\t\t\tquery: z.object({\n\t\t\t\t\tnamespace: z.string(),\n\t\t\t\t}),\n\t\t\t},\n\t\t\tresponses: buildOpenApiResponses(ActorsListNamesResponseSchema),\n\t\t});\n\n\t\trouter.openapi(route, async (c) => {\n\t\t\tconst names = buildActorNames(registryConfig);\n\t\t\treturn c.json<ActorsListNamesResponse>({\n\t\t\t\tnames,\n\t\t\t});\n\t\t});\n\t}\n\n\t// PUT /actors\n\t{\n\t\tconst route = createRoute({\n\t\t\tmethod: \"put\",\n\t\t\tpath: \"/actors\",\n\t\t\trequest: {\n\t\t\t\tbody: buildOpenApiRequestBody(ActorsGetOrCreateRequestSchema),\n\t\t\t},\n\t\t\tresponses: buildOpenApiResponses(ActorsGetOrCreateResponseSchema),\n\t\t});\n\n\t\trouter.openapi(route, async (c) => {\n\t\t\tconst body = c.req.valid(\"json\");\n\n\t\t\t// Check if actor already exists\n\t\t\tconst existingActor = await managerDriver.getWithKey({\n\t\t\t\tc,\n\t\t\t\tname: body.name,\n\t\t\t\tkey: [body.key], // Convert string to ActorKey array\n\t\t\t});\n\n\t\t\tif (existingActor) {\n\t\t\t\treturn c.json<ActorsGetOrCreateResponse>({\n\t\t\t\t\tactor: createApiActor(existingActor, runConfig.runnerName),\n\t\t\t\t\tcreated: false,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Create new actor\n\t\t\tconst newActor = await managerDriver.getOrCreateWithKey({\n\t\t\t\tc,\n\t\t\t\tname: body.name,\n\t\t\t\tkey: [body.key], // Convert string to ActorKey array\n\t\t\t\tinput: body.input\n\t\t\t\t\t? cbor.decode(Buffer.from(body.input, \"base64\"))\n\t\t\t\t\t: undefined,\n\t\t\t\tregion: undefined, // Not provided in the request schema\n\t\t\t});\n\n\t\t\treturn c.json<ActorsGetOrCreateResponse>({\n\t\t\t\tactor: createApiActor(newActor, runConfig.runnerName),\n\t\t\t\tcreated: true,\n\t\t\t});\n\t\t});\n\t}\n\n\t// POST /actors\n\t{\n\t\tconst route = createRoute({\n\t\t\tmethod: \"post\",\n\t\t\tpath: \"/actors\",\n\t\t\trequest: {\n\t\t\t\tbody: buildOpenApiRequestBody(ActorsCreateRequestSchema),\n\t\t\t},\n\t\t\tresponses: buildOpenApiResponses(ActorsCreateResponseSchema),\n\t\t});\n\n\t\trouter.openapi(route, async (c) => {\n\t\t\tconst body = c.req.valid(\"json\");\n\n\t\t\t// Create actor using the driver\n\t\t\tconst actorOutput = await managerDriver.createActor({\n\t\t\t\tc,\n\t\t\t\tname: body.name,\n\t\t\t\tkey: [body.key || crypto.randomUUID()], // Generate key if not provided, convert to ActorKey array\n\t\t\t\tinput: body.input\n\t\t\t\t\t? cbor.decode(Buffer.from(body.input, \"base64\"))\n\t\t\t\t\t: undefined,\n\t\t\t\tregion: undefined, // Not provided in the request schema\n\t\t\t});\n\n\t\t\t// Transform ActorOutput to match ActorSchema\n\t\t\tconst actor = createApiActor(actorOutput, runConfig.runnerName);\n\n\t\t\treturn c.json<ActorsCreateResponse>({ actor });\n\t\t});\n\t}\n\n\t// TODO:\n\t// // DELETE /actors/{actor_id}\n\t// {\n\t// \tconst route = createRoute({\n\t// \t\tmethod: \"delete\",\n\t// \t\tpath: \"/actors/{actor_id}\",\n\t// \t\trequest: {\n\t// \t\t\tparams: z.object({\n\t// \t\t\t\tactor_id: RivetIdSchema,\n\t// \t\t\t}),\n\t// \t\t},\n\t// \t\tresponses: buildOpenApiResponses(\n\t// \t\t\tActorsDeleteResponseSchema,\n\t// \t\t\tvalidateBody,\n\t// \t\t),\n\t// \t});\n\t//\n\t// \trouter.openapi(route, async (c) => {\n\t// \t\tconst { actor_id } = c.req.valid(\"param\");\n\t//\n\t// \t});\n\t// }\n\n\tif (registryConfig.test.enabled) {\n\t\t// Add HTTP endpoint to test the inline client\n\t\t//\n\t\t// We have to do this in a router since this needs to run in the same server as the RivetKit registry. Some test contexts to not run in the same server.\n\t\trouter.post(\".test/inline-driver/call\", async (c) => {\n\t\t\t// TODO: use openapi instead\n\t\t\tconst buffer = await c.req.arrayBuffer();\n\t\t\tconst { encoding, method, args }: TestInlineDriverCallRequest =\n\t\t\t\tcbor.decode(new Uint8Array(buffer));\n\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"received inline request\",\n\t\t\t\tencoding,\n\t\t\t\tmethod,\n\t\t\t\targs,\n\t\t\t});\n\n\t\t\t// Forward inline driver request\n\t\t\tlet response: TestInlineDriverCallResponse<unknown>;\n\t\t\ttry {\n\t\t\t\tconst output = await ((managerDriver as any)[method] as any)(\n\t\t\t\t\t...args,\n\t\t\t\t);\n\t\t\t\tresponse = { ok: output };\n\t\t\t} catch (rawErr) {\n\t\t\t\tconst err = deconstructError(rawErr, logger(), {}, true);\n\t\t\t\tresponse = { err };\n\t\t\t}\n\n\t\t\t// TODO: Remove any\n\t\t\treturn c.body(cbor.encode(response) as any);\n\t\t});\n\n\t\trouter.get(\".test/inline-driver/connect-websocket/*\", async (c) => {\n\t\t\tconst upgradeWebSocket = runConfig.getUpgradeWebSocket?.();\n\t\t\tinvariant(\n\t\t\t\tupgradeWebSocket,\n\t\t\t\t\"websockets not supported on this platform\",\n\t\t\t);\n\n\t\t\treturn upgradeWebSocket(async (c: any) => {\n\t\t\t\t// Extract information from sec-websocket-protocol header\n\t\t\t\tconst protocolHeader =\n\t\t\t\t\tc.req.header(\"sec-websocket-protocol\") || \"\";\n\t\t\t\tconst protocols = protocolHeader.split(/,\\s*/);\n\n\t\t\t\t// Parse protocols to extract connection info\n\t\t\t\tlet actorId = \"\";\n\t\t\t\tlet encoding: Encoding = \"bare\";\n\t\t\t\tlet path = \"\";\n\t\t\t\tlet params: unknown;\n\n\t\t\t\tfor (const protocol of protocols) {\n\t\t\t\t\tif (protocol.startsWith(WS_PROTOCOL_ACTOR)) {\n\t\t\t\t\t\tactorId = decodeURIComponent(\n\t\t\t\t\t\t\tprotocol.substring(WS_PROTOCOL_ACTOR.length),\n\t\t\t\t\t\t);\n\t\t\t\t\t} else if (protocol.startsWith(WS_PROTOCOL_ENCODING)) {\n\t\t\t\t\t\tencoding = protocol.substring(\n\t\t\t\t\t\t\tWS_PROTOCOL_ENCODING.length,\n\t\t\t\t\t\t) as Encoding;\n\t\t\t\t\t} else if (protocol.startsWith(WS_TEST_PROTOCOL_PATH)) {\n\t\t\t\t\t\tpath = decodeURIComponent(\n\t\t\t\t\t\t\tprotocol.substring(WS_TEST_PROTOCOL_PATH.length),\n\t\t\t\t\t\t);\n\t\t\t\t\t} else if (protocol.startsWith(WS_PROTOCOL_CONN_PARAMS)) {\n\t\t\t\t\t\tconst paramsRaw = decodeURIComponent(\n\t\t\t\t\t\t\tprotocol.substring(WS_PROTOCOL_CONN_PARAMS.length),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tparams = JSON.parse(paramsRaw);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlogger().debug({\n\t\t\t\t\tmsg: \"received test inline driver websocket\",\n\t\t\t\t\tactorId,\n\t\t\t\t\tparams,\n\t\t\t\t\tencodingKind: encoding,\n\t\t\t\t\tpath: path,\n\t\t\t\t});\n\n\t\t\t\t// Connect to the actor using the inline client driver - this returns a Promise<WebSocket>\n\t\t\t\tconst clientWsPromise = managerDriver.openWebSocket(\n\t\t\t\t\tpath,\n\t\t\t\t\tactorId,\n\t\t\t\t\tencoding,\n\t\t\t\t\tparams,\n\t\t\t\t);\n\n\t\t\t\treturn await createTestWebSocketProxy(clientWsPromise);\n\t\t\t})(c, noopNext());\n\t\t});\n\n\t\trouter.all(\".test/inline-driver/send-request/*\", async (c) => {\n\t\t\t// Extract parameters from headers\n\t\t\tconst actorId = c.req.header(HEADER_ACTOR_ID);\n\n\t\t\tif (!actorId) {\n\t\t\t\treturn c.text(\"Missing required headers\", 400);\n\t\t\t}\n\n\t\t\t// Extract the path after /send-request/\n\t\t\tconst pathOnly =\n\t\t\t\tc.req.path.split(\"/.test/inline-driver/send-request/\")[1] || \"\";\n\n\t\t\t// Include query string\n\t\t\tconst url = new URL(c.req.url);\n\t\t\tconst pathWithQuery = pathOnly + url.search;\n\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"received test inline driver raw http\",\n\t\t\t\tactorId,\n\t\t\t\tpath: pathWithQuery,\n\t\t\t\tmethod: c.req.method,\n\t\t\t});\n\n\t\t\ttry {\n\t\t\t\t// Forward the request using the inline client driver\n\t\t\t\tconst response = await managerDriver.sendRequest(\n\t\t\t\t\tactorId,\n\t\t\t\t\tnew Request(`http://actor/${pathWithQuery}`, {\n\t\t\t\t\t\tmethod: c.req.method,\n\t\t\t\t\t\theaders: c.req.raw.headers,\n\t\t\t\t\t\tbody: c.req.raw.body,\n\t\t\t\t\t\tduplex: \"half\",\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\t\t// Return the response directly\n\t\t\t\treturn response;\n\t\t\t} catch (error) {\n\t\t\t\tlogger().error({\n\t\t\t\t\tmsg: \"error in test inline raw http\",\n\t\t\t\t\terror: stringifyError(error),\n\t\t\t\t});\n\n\t\t\t\t// Return error response\n\t\t\t\tconst err = deconstructError(error, logger(), {}, true);\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tcode: err.code,\n\t\t\t\t\t\t\tmessage: err.message,\n\t\t\t\t\t\t\tmetadata: err.metadata,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\terr.statusCode,\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\n\t\t// Test endpoint to force disconnect a connection non-cleanly\n\t\trouter.post(\"/.test/force-disconnect\", async (c) => {\n\t\t\tconst actorId = c.req.query(\"actor\");\n\t\t\tconst connId = c.req.query(\"conn\");\n\n\t\t\tif (!actorId || !connId) {\n\t\t\t\treturn c.text(\"Missing actor or conn query parameters\", 400);\n\t\t\t}\n\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"forcing unclean disconnect\",\n\t\t\t\tactorId,\n\t\t\t\tconnId,\n\t\t\t});\n\n\t\t\ttry {\n\t\t\t\t// Send a special request to the actor to force disconnect the connection\n\t\t\t\tconst response = await managerDriver.sendRequest(\n\t\t\t\t\tactorId,\n\t\t\t\t\tnew Request(\n\t\t\t\t\t\t`http://actor/.test/force-disconnect?conn=${connId}`,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tconst text = await response.text();\n\t\t\t\t\treturn c.text(\n\t\t\t\t\t\t`Failed to force disconnect: ${text}`,\n\t\t\t\t\t\tresponse.status as any,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn c.json({ success: true });\n\t\t\t} catch (error) {\n\t\t\t\tlogger().error({\n\t\t\t\t\tmsg: \"error forcing disconnect\",\n\t\t\t\t\terror: stringifyError(error),\n\t\t\t\t});\n\t\t\t\treturn c.text(`Error: ${error}`, 500);\n\t\t\t}\n\t\t});\n\t}\n\n\trouter.get(\"/health\", (c) => handleHealthRequest(c));\n\n\trouter.get(\"/metadata\", (c) =>\n\t\thandleMetadataRequest(c, registryConfig, runConfig),\n\t);\n\n\tmanagerDriver.modifyManagerRouter?.(\n\t\tregistryConfig,\n\t\trouter as unknown as Hono,\n\t);\n}\n\nfunction createApiActor(\n\tactor: ActorOutput,\n\trunnerName: string = \"default\",\n): ApiActor {\n\treturn {\n\t\tactor_id: actor.actorId,\n\t\tname: actor.name,\n\t\tkey: serializeActorKey(actor.key),\n\t\tnamespace_id: \"default\", // Assert default namespace\n\t\trunner_name_selector: runnerName,\n\t\tcreate_ts: actor.createTs ?? Date.now(),\n\t\tconnectable_ts: actor.connectableTs ?? null,\n\t\tdestroy_ts: actor.destroyTs ?? null,\n\t\tsleep_ts: actor.sleepTs ?? null,\n\t\tstart_ts: actor.startTs ?? null,\n\t};\n}\n","import type { MiddlewareHandler } from \"hono\";\n\n/**\n * Simple CORS middleware that matches the gateway behavior.\n *\n * - Echoes back the Origin header from the request\n * - Echoes back the Access-Control-Request-Headers from preflight\n * - Supports credentials\n * - Allows common HTTP methods\n * - Caches preflight for 24 hours\n * - Adds Vary header to prevent cache poisoning\n */\nexport const cors = (): MiddlewareHandler => {\n\treturn async (c, next) => {\n\t\t// Extract origin from request\n\t\tconst origin = c.req.header(\"origin\") || \"*\";\n\n\t\t// Handle preflight OPTIONS request\n\t\tif (c.req.method === \"OPTIONS\") {\n\t\t\tconst requestHeaders =\n\t\t\t\tc.req.header(\"access-control-request-headers\") || \"*\";\n\n\t\t\tc.header(\"access-control-allow-origin\", origin);\n\t\t\tc.header(\"access-control-allow-credentials\", \"true\");\n\t\t\tc.header(\n\t\t\t\t\"access-control-allow-methods\",\n\t\t\t\t\"GET, POST, PUT, DELETE, OPTIONS, PATCH\",\n\t\t\t);\n\t\t\tc.header(\"access-control-allow-headers\", requestHeaders);\n\t\t\tc.header(\"access-control-expose-headers\", \"*\");\n\t\t\tc.header(\"access-control-max-age\", \"86400\");\n\n\t\t\t// Add Vary header to prevent cache poisoning when echoing origin\n\t\t\tif (origin !== \"*\") {\n\t\t\t\tc.header(\"vary\", \"Origin\");\n\t\t\t}\n\n\t\t\t// Remove content headers from preflight response\n\t\t\tc.res.headers.delete(\"content-length\");\n\t\t\tc.res.headers.delete(\"content-type\");\n\n\t\t\treturn c.body(null, 204);\n\t\t}\n\n\t\tawait next();\n\n\t\t// Add CORS headers to actual request\n\t\tc.header(\"access-control-allow-origin\", origin);\n\t\tc.header(\"access-control-allow-credentials\", \"true\");\n\t\tc.header(\"access-control-expose-headers\", \"*\");\n\n\t\t// Add Vary header to prevent cache poisoning when echoing origin\n\t\tif (origin !== \"*\") {\n\t\t\tc.header(\"vary\", \"Origin\");\n\t\t}\n\t};\n};\n","import { z } from \"zod\";\nimport { RivetIdSchema } from \"./common\";\n\nexport const ActorSchema = z.object({\n\tactor_id: RivetIdSchema,\n\tname: z.string(),\n\tkey: z.string(),\n\tnamespace_id: RivetIdSchema,\n\trunner_name_selector: z.string(),\n\tcreate_ts: z.number(),\n\tconnectable_ts: z.number().nullable().optional(),\n\tdestroy_ts: z.number().nullable().optional(),\n\tsleep_ts: z.number().nullable().optional(),\n\tstart_ts: z.number().nullable().optional(),\n});\nexport type Actor = z.infer<typeof ActorSchema>;\n\nexport const ActorNameSchema = z.object({\n\tmetadata: z.record(z.string(), z.unknown()),\n});\nexport type ActorName = z.infer<typeof ActorNameSchema>;\n\n// MARK: GET /actors\nexport const ActorsListResponseSchema = z.object({\n\tactors: z.array(ActorSchema),\n});\nexport type ActorsListResponse = z.infer<typeof ActorsListResponseSchema>;\n\n// MARK: POST /actors\nexport const ActorsCreateRequestSchema = z.object({\n\tdatacenter: z.string().optional(),\n\tname: z.string(),\n\trunner_name_selector: z.string(),\n\tcrash_policy: z.string(),\n\tkey: z.string().nullable().optional(),\n\tinput: z.string().nullable().optional(),\n});\nexport type ActorsCreateRequest = z.infer<typeof ActorsCreateRequestSchema>;\n\nexport const ActorsCreateResponseSchema = z.object({\n\tactor: ActorSchema,\n});\nexport type ActorsCreateResponse = z.infer<typeof ActorsCreateResponseSchema>;\n\n// MARK: PUT /actors\nexport const ActorsGetOrCreateRequestSchema = z.object({\n\tdatacenter: z.string().optional(),\n\tname: z.string(),\n\tkey: z.string(),\n\trunner_name_selector: z.string(),\n\tcrash_policy: z.string(),\n\tinput: z.string().nullable().optional(),\n});\nexport type ActorsGetOrCreateRequest = z.infer<\n\ttypeof ActorsGetOrCreateRequestSchema\n>;\n\nexport const ActorsGetOrCreateResponseSchema = z.object({\n\tactor: ActorSchema,\n\tcreated: z.boolean(),\n});\nexport type ActorsGetOrCreateResponse = z.infer<\n\ttypeof ActorsGetOrCreateResponseSchema\n>;\n\n// MARK: DELETE /actors/{}\nexport const ActorsDeleteResponseSchema = z.object({});\nexport type ActorsDeleteResponse = z.infer<typeof ActorsDeleteResponseSchema>;\n\n// MARK: GET /actors/names\nexport const ActorsListNamesResponseSchema = z.object({\n\tnames: z.record(z.string(), ActorNameSchema),\n});\nexport type ActorsListNamesResponse = z.infer<\n\ttypeof ActorsListNamesResponseSchema\n>;\n","import { z } from \"zod\";\n\nexport const RivetIdSchema = z.string();\nexport type RivetId = z.infer<typeof RivetIdSchema>;\n","import { getLogger } from \"@/common/log\";\n\nexport function logger() {\n\treturn getLogger(\"actor-manager\");\n}\n","import type { Context as HonoContext, Next } from \"hono\";\nimport type { WSContext } from \"hono/ws\";\nimport { MissingActorHeader, WebSocketsNotEnabled } from \"@/actor/errors\";\nimport type { UpgradeWebSocketArgs } from \"@/actor/router-websocket-endpoints\";\nimport {\n\tHEADER_RIVET_ACTOR,\n\tHEADER_RIVET_TARGET,\n\tWS_PROTOCOL_ACTOR,\n\tWS_PROTOCOL_CONN_PARAMS,\n\tWS_PROTOCOL_ENCODING,\n\tWS_PROTOCOL_TARGET,\n} from \"@/common/actor-router-consts\";\nimport type { UniversalWebSocket } from \"@/mod\";\nimport type { RunnerConfig } from \"@/registry/run-config\";\nimport { promiseWithResolvers } from \"@/utils\";\nimport type { ManagerDriver } from \"./driver\";\nimport { logger } from \"./log\";\n\ninterface ActorPathInfo {\n\tactorId: string;\n\ttoken?: string;\n\tremainingPath: string;\n}\n\n/**\n * Handle path-based WebSocket routing\n */\nasync function handleWebSocketGatewayPathBased(\n\trunConfig: RunnerConfig,\n\tmanagerDriver: ManagerDriver,\n\tc: HonoContext,\n\tactorPathInfo: ActorPathInfo,\n): Promise<Response> {\n\tconst upgradeWebSocket = runConfig.getUpgradeWebSocket?.();\n\tif (!upgradeWebSocket) {\n\t\tthrow new WebSocketsNotEnabled();\n\t}\n\n\t// NOTE: Token validation implemented in EE\n\n\t// Parse additional configuration from Sec-WebSocket-Protocol header\n\tconst protocols = c.req.header(\"sec-websocket-protocol\");\n\tlet encodingRaw: string | undefined;\n\tlet connParamsRaw: string | undefined;\n\n\tif (protocols) {\n\t\tconst protocolList = protocols.split(\",\").map((p) => p.trim());\n\t\tfor (const protocol of protocolList) {\n\t\t\tif (protocol.startsWith(WS_PROTOCOL_ENCODING)) {\n\t\t\t\tencodingRaw = protocol.substring(WS_PROTOCOL_ENCODING.length);\n\t\t\t} else if (protocol.startsWith(WS_PROTOCOL_CONN_PARAMS)) {\n\t\t\t\tconnParamsRaw = decodeURIComponent(\n\t\t\t\t\tprotocol.substring(WS_PROTOCOL_CONN_PARAMS.length),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tlogger().debug({\n\t\tmsg: \"proxying websocket to actor via path-based routing\",\n\t\tactorId: actorPathInfo.actorId,\n\t\tpath: actorPathInfo.remainingPath,\n\t\tencoding: encodingRaw,\n\t});\n\n\tconst encoding = encodingRaw || \"json\";\n\tconst connParams = connParamsRaw ? JSON.parse(connParamsRaw) : undefined;\n\n\treturn await managerDriver.proxyWebSocket(\n\t\tc,\n\t\tactorPathInfo.remainingPath,\n\t\tactorPathInfo.actorId,\n\t\tencoding as any, // Will be validated by driver\n\t\tconnParams,\n\t);\n}\n\n/**\n * Handle path-based HTTP routing\n */\nasync function handleHttpGatewayPathBased(\n\tmanagerDriver: ManagerDriver,\n\tc: HonoContext,\n\tactorPathInfo: ActorPathInfo,\n): Promise<Response> {\n\t// NOTE: Token validation implemented in EE\n\n\tlogger().debug({\n\t\tmsg: \"proxying request to actor via path-based routing\",\n\t\tactorId: actorPathInfo.actorId,\n\t\tpath: actorPathInfo.remainingPath,\n\t\tmethod: c.req.method,\n\t});\n\n\t// Preserve all headers\n\tconst proxyHeaders = new Headers(c.req.raw.headers);\n\n\t// Build the proxy request with the actor URL format\n\tconst proxyUrl = new URL(`http://actor${actorPathInfo.remainingPath}`);\n\n\tconst proxyRequest = new Request(proxyUrl, {\n\t\tmethod: c.req.raw.method,\n\t\theaders: proxyHeaders,\n\t\tbody: c.req.raw.body,\n\t\tsignal: c.req.raw.signal,\n\t\tduplex: \"half\",\n\t} as RequestInit);\n\n\treturn await managerDriver.proxyRequest(\n\t\tc,\n\t\tproxyRequest,\n\t\tactorPathInfo.actorId,\n\t);\n}\n\n/**\n * Provides an endpoint to connect to individual actors.\n *\n * Routes requests using either path-based routing or header-based routing:\n *\n * Path-based routing (checked first):\n * - /gateway/{actor_id}/{...path}\n * - /gateway/{actor_id}@{token}/{...path}\n *\n * Header-based routing (fallback):\n * - WebSocket requests: Uses sec-websocket-protocol for routing (target.actor, actor.{id})\n * - HTTP requests: Uses x-rivet-target and x-rivet-actor headers for routing\n */\nexport async function actorGateway(\n\trunConfig: RunnerConfig,\n\tmanagerDriver: ManagerDriver,\n\tc: HonoContext,\n\tnext: Next,\n) {\n\t// Skip test routes - let them be handled by their specific handlers\n\tif (c.req.path.startsWith(\"/.test/\")) {\n\t\treturn next();\n\t}\n\n\t// Strip basePath from the request path\n\tlet strippedPath = c.req.path;\n\tif (runConfig.basePath && strippedPath.startsWith(runConfig.basePath)) {\n\t\tstrippedPath = strippedPath.slice(runConfig.basePath.length);\n\t\t// Ensure the path starts with /\n\t\tif (!strippedPath.startsWith(\"/\")) {\n\t\t\tstrippedPath = \"/\" + strippedPath;\n\t\t}\n\t}\n\n\t// Include query string if present (needed for parseActorPath to preserve query params)\n\tconst pathWithQuery = c.req.url.includes(\"?\")\n\t\t? strippedPath + c.req.url.substring(c.req.url.indexOf(\"?\"))\n\t\t: strippedPath;\n\n\t// First, check if this is an actor path-based route\n\tconst actorPathInfo = parseActorPath(pathWithQuery);\n\tif (actorPathInfo) {\n\t\tlogger().debug({\n\t\t\tmsg: \"routing using path-based actor routing\",\n\t\t\tactorPathInfo,\n\t\t});\n\n\t\t// Check if this is a WebSocket upgrade request\n\t\tconst isWebSocket = c.req.header(\"upgrade\") === \"websocket\";\n\n\t\tif (isWebSocket) {\n\t\t\treturn await handleWebSocketGatewayPathBased(\n\t\t\t\trunConfig,\n\t\t\t\tmanagerDriver,\n\t\t\t\tc,\n\t\t\t\tactorPathInfo,\n\t\t\t);\n\t\t}\n\n\t\t// Handle regular HTTP requests\n\t\treturn await handleHttpGatewayPathBased(\n\t\t\tmanagerDriver,\n\t\t\tc,\n\t\t\tactorPathInfo,\n\t\t);\n\t}\n\n\t// Fallback to header-based routing\n\t// Check if this is a WebSocket upgrade request\n\tif (c.req.header(\"upgrade\") === \"websocket\") {\n\t\treturn await handleWebSocketGateway(\n\t\t\trunConfig,\n\t\t\tmanagerDriver,\n\t\t\tc,\n\t\t\tstrippedPath,\n\t\t);\n\t}\n\n\t// Handle regular HTTP requests\n\treturn await handleHttpGateway(managerDriver, c, next, strippedPath);\n}\n\n/**\n * Handle WebSocket requests using sec-websocket-protocol for routing\n */\nasync function handleWebSocketGateway(\n\trunConfig: RunnerConfig,\n\tmanagerDriver: ManagerDriver,\n\tc: HonoContext,\n\tstrippedPath: string,\n) {\n\tconst upgradeWebSocket = runConfig.getUpgradeWebSocket?.();\n\tif (!upgradeWebSocket) {\n\t\tthrow new WebSocketsNotEnabled();\n\t}\n\n\t// Parse configuration from Sec-WebSocket-Protocol header\n\tconst protocols = c.req.header(\"sec-websocket-protocol\");\n\tlet target: string | undefined;\n\tlet actorId: string | undefined;\n\tlet encodingRaw: string | undefined;\n\tlet connParamsRaw: string | undefined;\n\n\tif (protocols) {\n\t\tconst protocolList = protocols.split(\",\").map((p) => p.trim());\n\t\tfor (const protocol of protocolList) {\n\t\t\tif (protocol.startsWith(WS_PROTOCOL_TARGET)) {\n\t\t\t\ttarget = protocol.substring(WS_PROTOCOL_TARGET.length);\n\t\t\t} else if (protocol.startsWith(WS_PROTOCOL_ACTOR)) {\n\t\t\t\tactorId = decodeURIComponent(\n\t\t\t\t\tprotocol.substring(WS_PROTOCOL_ACTOR.length),\n\t\t\t\t);\n\t\t\t} else if (protocol.startsWith(WS_PROTOCOL_ENCODING)) {\n\t\t\t\tencodingRaw = protocol.substring(WS_PROTOCOL_ENCODING.length);\n\t\t\t} else if (protocol.startsWith(WS_PROTOCOL_CONN_PARAMS)) {\n\t\t\t\tconnParamsRaw = decodeURIComponent(\n\t\t\t\t\tprotocol.substring(WS_PROTOCOL_CONN_PARAMS.length),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (target !== \"actor\") {\n\t\treturn c.text(\"WebSocket upgrade requires target.actor protocol\", 400);\n\t}\n\n\tif (!actorId) {\n\t\tthrow new MissingActorHeader();\n\t}\n\n\tlogger().debug({\n\t\tmsg: \"proxying websocket to actor\",\n\t\tactorId,\n\t\tpath: strippedPath,\n\t\tencoding: encodingRaw,\n\t});\n\n\tconst encoding = encodingRaw || \"json\";\n\tconst connParams = connParamsRaw ? JSON.parse(connParamsRaw) : undefined;\n\n\t// Include query string if present\n\tconst pathWithQuery = c.req.url.includes(\"?\")\n\t\t? strippedPath + c.req.url.substring(c.req.url.indexOf(\"?\"))\n\t\t: strippedPath;\n\n\treturn await managerDriver.proxyWebSocket(\n\t\tc,\n\t\tpathWithQuery,\n\t\tactorId,\n\t\tencoding as any, // Will be validated by driver\n\t\tconnParams,\n\t);\n}\n\n/**\n * Handle HTTP requests using x-rivet headers for routing\n */\nasync function handleHttpGateway(\n\tmanagerDriver: ManagerDriver,\n\tc: HonoContext,\n\tnext: Next,\n\tstrippedPath: string,\n) {\n\tconst target = c.req.header(HEADER_RIVET_TARGET);\n\tconst actorId = c.req.header(HEADER_RIVET_ACTOR);\n\n\tif (target !== \"actor\") {\n\t\treturn next();\n\t}\n\n\tif (!actorId) {\n\t\tthrow new MissingActorHeader();\n\t}\n\n\tlogger().debug({\n\t\tmsg: \"proxying request to actor\",\n\t\tactorId,\n\t\tpath: strippedPath,\n\t\tmethod: c.req.method,\n\t});\n\n\t// Preserve all headers except the routing headers\n\tconst proxyHeaders = new Headers(c.req.raw.headers);\n\tproxyHeaders.delete(HEADER_RIVET_TARGET);\n\tproxyHeaders.delete(HEADER_RIVET_ACTOR);\n\n\t// Build the proxy request with the actor URL format\n\tconst url = new URL(c.req.url);\n\tconst proxyUrl = new URL(`http://actor${strippedPath}${url.search}`);\n\n\tconst proxyRequest = new Request(proxyUrl, {\n\t\tmethod: c.req.raw.method,\n\t\theaders: proxyHeaders,\n\t\tbody: c.req.raw.body,\n\t\tsignal: c.req.raw.signal,\n\t\tduplex: \"half\",\n\t} as RequestInit);\n\n\treturn await managerDriver.proxyRequest(c, proxyRequest, actorId);\n}\n\n/**\n * Parse actor routing information from path\n * Matches patterns:\n * - /gateway/{actor_id}/{...path}\n * - /gateway/{actor_id}@{token}/{...path}\n */\nexport function parseActorPath(path: string): ActorPathInfo | null {\n\t// Find query string position (everything from ? onwards, but before fragment)\n\tconst queryPos = path.indexOf(\"?\");\n\tconst fragmentPos = path.indexOf(\"#\");\n\n\t// Extract query string (excluding fragment)\n\tlet queryString = \"\";\n\tif (queryPos !== -1) {\n\t\tif (fragmentPos !== -1 && queryPos < fragmentPos) {\n\t\t\tqueryString = path.slice(queryPos, fragmentPos);\n\t\t} else {\n\t\t\tqueryString = path.slice(queryPos);\n\t\t}\n\t}\n\n\t// Extract base path (before query and fragment)\n\tlet basePath = path;\n\tif (queryPos !== -1) {\n\t\tbasePath = path.slice(0, queryPos);\n\t} else if (fragmentPos !== -1) {\n\t\tbasePath = path.slice(0, fragmentPos);\n\t}\n\n\t// Check for double slashes (invalid path)\n\tif (basePath.includes(\"//\")) {\n\t\treturn null;\n\t}\n\n\t// Split the path into segments\n\tconst segments = basePath.split(\"/\").filter((s) => s.length > 0);\n\n\t// Check minimum required segments: gateway, {actor_id}\n\tif (segments.length < 2) {\n\t\treturn null;\n\t}\n\n\t// Verify the first segment is \"gateway\"\n\tif (segments[0] !== \"gateway\") {\n\t\treturn null;\n\t}\n\n\t// Extract actor_id segment (may contain @token)\n\tconst actorSegment = segments[1];\n\n\t// Check for empty actor segment\n\tif (actorSegment.length === 0) {\n\t\treturn null;\n\t}\n\n\t// Parse actor_id and optional token from the segment\n\tlet actorId: string;\n\tlet token: string | undefined;\n\n\tconst atPos = actorSegment.indexOf(\"@\");\n\tif (atPos !== -1) {\n\t\t// Pattern: /gateway/{actor_id}@{token}/{...path}\n\t\tconst rawActorId = actorSegment.slice(0, atPos);\n\t\tconst rawToken = actorSegment.slice(atPos + 1);\n\n\t\t// Check for empty actor_id or token\n\t\tif (rawActorId.length === 0 || rawToken.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// URL-decode both actor_id and token\n\t\ttry {\n\t\t\tactorId = decodeURIComponent(rawActorId);\n\t\t\ttoken = decodeURIComponent(rawToken);\n\t\t} catch (e) {\n\t\t\t// Invalid URL encoding\n\t\t\treturn null;\n\t\t}\n\t} else {\n\t\t// Pattern: /gateway/{actor_id}/{...path}\n\t\t// URL-decode actor_id\n\t\ttry {\n\t\t\tactorId = decodeURIComponent(actorSegment);\n\t\t} catch (e) {\n\t\t\t// Invalid URL encoding\n\t\t\treturn null;\n\t\t}\n\t\ttoken = undefined;\n\t}\n\n\t// Calculate remaining path\n\t// The remaining path starts after /gateway/{actor_id[@token]}/\n\tlet prefixLen = 0;\n\tfor (let i = 0; i < 2; i++) {\n\t\tprefixLen += 1 + segments[i].length; // +1 for the slash\n\t}\n\n\t// Extract the remaining path preserving trailing slashes\n\tlet remainingBase: string;\n\tif (prefixLen < basePath.length) {\n\t\tremainingBase = basePath.slice(prefixLen);\n\t} else {\n\t\tremainingBase = \"/\";\n\t}\n\n\t// Ensure remaining path starts with /\n\tlet remainingPath: string;\n\tif (remainingBase.length === 0 || !remainingBase.startsWith(\"/\")) {\n\t\tremainingPath = `/${remainingBase}${queryString}`;\n\t} else {\n\t\tremainingPath = `${remainingBase}${queryString}`;\n\t}\n\n\treturn {\n\t\tactorId,\n\t\ttoken,\n\t\tremainingPath,\n\t};\n}\n\n/**\n * Creates a WebSocket proxy for test endpoints that forwards messages between server and client WebSockets\n */\nexport async function createTestWebSocketProxy(\n\tclientWsPromise: Promise<UniversalWebSocket>,\n): Promise<UpgradeWebSocketArgs> {\n\t// Store a reference to the resolved WebSocket\n\tlet clientWs: UniversalWebSocket | null = null;\n\tconst {\n\t\tpromise: serverWsPromise,\n\t\tresolve: serverWsResolve,\n\t\treject: serverWsReject,\n\t} = promiseWithResolvers<WSContext>();\n\ttry {\n\t\t// Resolve the client WebSocket promise\n\t\tlogger().debug({ msg: \"awaiting client websocket promise\" });\n\t\tconst ws = await clientWsPromise;\n\t\tclientWs = ws;\n\t\tlogger().debug({\n\t\t\tmsg: \"client websocket promise resolved\",\n\t\t\tconstructor: ws?.constructor.name,\n\t\t});\n\n\t\t// Wait for ws to open\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tconst onOpen = () => {\n\t\t\t\tlogger().debug({\n\t\t\t\t\tmsg: \"test websocket connection to actor opened\",\n\t\t\t\t});\n\t\t\t\tresolve();\n\t\t\t};\n\t\t\tconst onError = (error: any) => {\n\t\t\t\tlogger().error({\n\t\t\t\t\tmsg: \"test websocket connection failed\",\n\t\t\t\t\terror,\n\t\t\t\t});\n\t\t\t\treject(\n\t\t\t\t\tnew Error(\n\t\t\t\t\t\t`Failed to open WebSocket: ${error.message || error}`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tserverWsReject();\n\t\t\t};\n\n\t\t\tws.addEventListener(\"open\", onOpen);\n\n\t\t\tws.addEventListener(\"error\", onError);\n\n\t\t\tws.addEventListener(\"message\", async (clientEvt: MessageEvent) => {\n\t\t\t\tconst serverWs = await serverWsPromise;\n\n\t\t\t\tlogger().debug({\n\t\t\t\t\tmsg: `test websocket connection message from client`,\n\t\t\t\t\tdataType: typeof clientEvt.data,\n\t\t\t\t\tisBlob: clientEvt.data instanceof Blob,\n\t\t\t\t\tisArrayBuffer: clientEvt.data instanceof ArrayBuffer,\n\t\t\t\t\tdataConstructor: clientEvt.data?.constructor?.name,\n\t\t\t\t\tdataStr:\n\t\t\t\t\t\ttypeof clientEvt.data === \"string\"\n\t\t\t\t\t\t\t? clientEvt.data.substring(0, 100)\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t});\n\n\t\t\t\tif (serverWs.readyState === 1) {\n\t\t\t\t\t// OPEN\n\t\t\t\t\t// Handle Blob data\n\t\t\t\t\tif (clientEvt.data instanceof Blob) {\n\t\t\t\t\t\tclientEvt.data\n\t\t\t\t\t\t\t.arrayBuffer()\n\t\t\t\t\t\t\t.then((buffer) => {\n\t\t\t\t\t\t\t\tlogger().debug({\n\t\t\t\t\t\t\t\t\tmsg: \"converted client blob to arraybuffer, sending to server\",\n\t\t\t\t\t\t\t\t\tbufferSize: buffer.byteLength,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tserverWs.send(buffer as any);\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.catch((error) => {\n\t\t\t\t\t\t\t\tlogger().error({\n\t\t\t\t\t\t\t\t\tmsg: \"failed to convert blob to arraybuffer\",\n\t\t\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger().debug({\n\t\t\t\t\t\t\tmsg: \"sending client data directly to server\",\n\t\t\t\t\t\t\tdataType: typeof clientEvt.data,\n\t\t\t\t\t\t\tdataLength:\n\t\t\t\t\t\t\t\ttypeof clientEvt.data === \"string\"\n\t\t\t\t\t\t\t\t\t? clientEvt.data.length\n\t\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tserverWs.send(clientEvt.data as any);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tws.addEventListener(\"close\", async (clientEvt: any) => {\n\t\t\t\tconst serverWs = await serverWsPromise;\n\n\t\t\t\tlogger().debug({\n\t\t\t\t\tmsg: `test websocket connection closed`,\n\t\t\t\t});\n\n\t\t\t\tif (serverWs.readyState !== 3) {\n\t\t\t\t\t// Not CLOSED\n\t\t\t\t\tserverWs.close(clientEvt.code, clientEvt.reason);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tws.addEventListener(\"error\", async () => {\n\t\t\t\tconst serverWs = await serverWsPromise;\n\n\t\t\t\tlogger().debug({\n\t\t\t\t\tmsg: `test websocket connection error`,\n\t\t\t\t});\n\n\t\t\t\tif (serverWs.readyState !== 3) {\n\t\t\t\t\t// Not CLOSED\n\t\t\t\t\tserverWs.close(1011, \"Error in client websocket\");\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t} catch (error) {\n\t\tlogger().error({\n\t\t\tmsg: `failed to establish client websocket connection`,\n\t\t\terror,\n\t\t});\n\t\treturn {\n\t\t\tonOpen: (_evt, serverWs) => {\n\t\t\t\tserverWs.close(1011, \"Failed to establish connection\");\n\t\t\t},\n\t\t\tonMessage: () => {},\n\t\t\tonError: () => {},\n\t\t\tonClose: () => {},\n\t\t};\n\t}\n\n\t// Create WebSocket proxy handlers to relay messages between client and server\n\treturn {\n\t\tonOpen: (_evt: any, serverWs: WSContext) => {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: `test websocket connection from client opened`,\n\t\t\t});\n\n\t\t\t// Check WebSocket type\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"clientWs info\",\n\t\t\t\tconstructor: clientWs.constructor.name,\n\t\t\t\thasAddEventListener:\n\t\t\t\t\ttypeof clientWs.addEventListener === \"function\",\n\t\t\t\treadyState: clientWs.readyState,\n\t\t\t});\n\n\t\t\tserverWsResolve(serverWs);\n\t\t},\n\t\tonMessage: (evt: { data: any }) => {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: \"received message from server\",\n\t\t\t\tdataType: typeof evt.data,\n\t\t\t\tisBlob: evt.data instanceof Blob,\n\t\t\t\tisArrayBuffer: evt.data instanceof ArrayBuffer,\n\t\t\t\tdataConstructor: evt.data?.constructor?.name,\n\t\t\t\tdataStr:\n\t\t\t\t\ttypeof evt.data === \"string\"\n\t\t\t\t\t\t? evt.data.substring(0, 100)\n\t\t\t\t\t\t: undefined,\n\t\t\t});\n\n\t\t\t// Forward messages from server websocket to client websocket\n\t\t\tif (clientWs.readyState === 1) {\n\t\t\t\t// OPEN\n\t\t\t\t// Handle Blob data\n\t\t\t\tif (evt.data instanceof Blob) {\n\t\t\t\t\tevt.data\n\t\t\t\t\t\t.arrayBuffer()\n\t\t\t\t\t\t.then((buffer) => {\n\t\t\t\t\t\t\tlogger().debug({\n\t\t\t\t\t\t\t\tmsg: \"converted blob to arraybuffer, sending\",\n\t\t\t\t\t\t\t\tbufferSize: buffer.byteLength,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tclientWs.send(buffer);\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch((error) => {\n\t\t\t\t\t\t\tlogger().error({\n\t\t\t\t\t\t\t\tmsg: \"failed to convert blob to arraybuffer\",\n\t\t\t\t\t\t\t\terror,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tlogger().debug({\n\t\t\t\t\t\tmsg: \"sending data directly\",\n\t\t\t\t\t\tdataType: typeof evt.data,\n\t\t\t\t\t\tdataLength:\n\t\t\t\t\t\t\ttypeof evt.data === \"string\"\n\t\t\t\t\t\t\t\t? evt.data.length\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t});\n\t\t\t\t\tclientWs.send(evt.data);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tonClose: (\n\t\t\tevent: {\n\t\t\t\twasClean: boolean;\n\t\t\t\tcode: number;\n\t\t\t\treason: string;\n\t\t\t},\n\t\t\tserverWs: WSContext,\n\t\t) => {\n\t\t\tlogger().debug({\n\t\t\t\tmsg: `server websocket closed`,\n\t\t\t\twasClean: event.wasClean,\n\t\t\t\tcode: event.code,\n\t\t\t\treason: event.reason,\n\t\t\t});\n\n\t\t\t// HACK: Close socket in order to fix bug with Cloudflare leaving WS in closing state\n\t\t\t// https://github.com/cloudflare/workerd/issues/2569\n\t\t\tserverWs.close(1000, \"hack_force_close\");\n\n\t\t\t// Close the client websocket when the server websocket closes\n\t\t\tif (\n\t\t\t\tclientWs &&\n\t\t\t\tclientWs.readyState !== clientWs.CLOSED &&\n\t\t\t\tclientWs.readyState !== clientWs.CLOSING\n\t\t\t) {\n\t\t\t\t// Don't pass code/message since this may affect how close events are triggered\n\t\t\t\tclientWs.close(1000, event.reason);\n\t\t\t}\n\t\t},\n\t\tonError: (error: unknown) => {\n\t\t\tlogger().error({\n\t\t\t\tmsg: `error in server websocket`,\n\t\t\t\terror,\n\t\t\t});\n\n\t\t\t// Close the client websocket on error\n\t\t\tif (\n\t\t\t\tclientWs &&\n\t\t\t\tclientWs.readyState !== clientWs.CLOSED &&\n\t\t\t\tclientWs.readyState !== clientWs.CLOSING\n\t\t\t) {\n\t\t\t\tclientWs.close(1011, \"Error in server websocket\");\n\t\t\t}\n\n\t\t\tserverWsReject();\n\t\t},\n\t};\n}\n","import { z } from \"zod\";\n\nexport const ServerlessStartHeadersSchema = z.object({\n\tendpoint: z.string({\n\t\terror: \"x-rivet-endpoint header is required\",\n\t}),\n\ttoken: z\n\t\t.string({ error: \"x-rivet-token header must be a string\" })\n\t\t.optional(),\n\ttotalSlots: z.coerce\n\t\t.number({\n\t\t\terror: \"x-rivet-total-slots header must be a number\",\n\t\t})\n\t\t.int({ error: \"x-rivet-total-slots header must be an integer\" })\n\t\t.gte(1, { error: \"x-rivet-total-slots header must be positive\" }),\n\trunnerName: z.string({\n\t\terror: \"x-rivet-runner-name header is required\",\n\t}),\n\tnamespace: z.string({\n\t\terror: \"x-rivet-namespace-name header is required\",\n\t}),\n});\n","import { getLogger } from \"@/common/log\";\n\nexport function logger() {\n\treturn getLogger(\"registry\");\n}\n","import type { Hono } from \"hono\";\nimport { logger } from \"./log\";\nimport type { RunnerConfig } from \"./run-config\";\n\nexport async function crossPlatformServe(\n\trunConfig: RunnerConfig,\n\tapp: Hono<any>,\n) {\n\t// Import @hono/node-server using string variable to prevent static analysis\n\tconst nodeServerModule = \"@hono/node-server\";\n\tlet serve: any;\n\ttry {\n\t\tconst dep = await import(\n\t\t\t/* webpackIgnore: true */\n\t\t\tnodeServerModule\n\t\t);\n\t\tserve = dep.serve;\n\t} catch (err) {\n\t\tlogger().error(\n\t\t\t\"failed to import @hono/node-server. please run 'npm install @hono/node-server @hono/node-ws'\",\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\t// Import @hono/node-ws using string variable to prevent static analysis\n\tconst nodeWsModule = \"@hono/node-ws\";\n\tlet createNodeWebSocket: any;\n\ttry {\n\t\tconst dep = await import(\n\t\t\t/* webpackIgnore: true */\n\t\t\tnodeWsModule\n\t\t);\n\t\tcreateNodeWebSocket = dep.createNodeWebSocket;\n\t} catch (err) {\n\t\tlogger().error(\n\t\t\t\"failed to import @hono/node-ws. please run 'npm install @hono/node-server @hono/node-ws'\",\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\t// Inject WS\n\tconst { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({\n\t\tapp: app,\n\t});\n\n\t// Start server\n\tconst port = runConfig.defaultServerPort;\n\tconst server = serve({ fetch: app.fetch, port }, () =>\n\t\tlogger().info({ msg: \"server listening\", port }),\n\t);\n\tinjectWebSocket(server);\n\n\treturn { upgradeWebSocket };\n}\n"]}