durable-actors 0.2.5 → 0.2.7

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 (268) hide show
  1. package/README.md +102 -139
  2. package/dist/actor/actor.d.ts +25 -0
  3. package/dist/actor/actor.d.ts.map +1 -1
  4. package/dist/actor/actor.js +17 -0
  5. package/dist/actor/actor.js.map +1 -1
  6. package/dist/actor/decorators.d.ts +8 -0
  7. package/dist/actor/decorators.d.ts.map +1 -1
  8. package/dist/actor/decorators.js +8 -0
  9. package/dist/actor/decorators.js.map +1 -1
  10. package/dist/actor/socket.d.ts +26 -0
  11. package/dist/actor/socket.d.ts.map +1 -1
  12. package/dist/actor/socket.js.map +1 -1
  13. package/dist/actor/socketValidation.d.ts +3 -0
  14. package/dist/actor/socketValidation.d.ts.map +1 -1
  15. package/dist/actor/socketValidation.js.map +1 -1
  16. package/dist/backend.d.ts +5 -3
  17. package/dist/backend.d.ts.map +1 -1
  18. package/dist/backend.js +3 -0
  19. package/dist/backend.js.map +1 -1
  20. package/dist/cli/actor-source-watcher.js +1 -1
  21. package/dist/cli/actor-source-watcher.js.map +1 -1
  22. package/dist/cli/connection.d.ts +2 -8
  23. package/dist/cli/connection.d.ts.map +1 -1
  24. package/dist/cli/connection.js +17 -13
  25. package/dist/cli/connection.js.map +1 -1
  26. package/dist/cli/control-plane.d.ts +7 -14
  27. package/dist/cli/control-plane.d.ts.map +1 -1
  28. package/dist/cli/control-plane.js +17 -21
  29. package/dist/cli/control-plane.js.map +1 -1
  30. package/dist/cli/dev.d.ts +13 -2
  31. package/dist/cli/dev.d.ts.map +1 -1
  32. package/dist/cli/dev.js +28 -20
  33. package/dist/cli/dev.js.map +1 -1
  34. package/dist/cli/generate.d.ts.map +1 -1
  35. package/dist/cli/generate.js +15 -28
  36. package/dist/cli/generate.js.map +1 -1
  37. package/dist/cli/observe.d.ts +2 -2
  38. package/dist/cli/observe.d.ts.map +1 -1
  39. package/dist/cli/observe.js +23 -42
  40. package/dist/cli/observe.js.map +1 -1
  41. package/dist/cli/start.d.ts +3 -0
  42. package/dist/cli/start.d.ts.map +1 -0
  43. package/dist/cli/start.js +12 -0
  44. package/dist/cli/start.js.map +1 -0
  45. package/dist/cli.js +8 -35
  46. package/dist/cli.js.map +1 -1
  47. package/dist/client/actorHostGrpc.js +2 -2
  48. package/dist/client/clientSettings.js +1 -1
  49. package/dist/client/remoteClient.d.ts +3 -3
  50. package/dist/client/remoteClient.d.ts.map +1 -1
  51. package/dist/client/remoteClient.js +4 -5
  52. package/dist/client/remoteClient.js.map +1 -1
  53. package/dist/errors.d.ts +3 -0
  54. package/dist/errors.d.ts.map +1 -1
  55. package/dist/errors.js +3 -0
  56. package/dist/errors.js.map +1 -1
  57. package/dist/generated/{durable_object → durable_actors}/v1/ActivateActorReply.d.ts.map +1 -1
  58. package/dist/generated/durable_actors/v1/ActivateActorReply.js +3 -0
  59. package/dist/generated/durable_actors/v1/ActivateActorReply.js.map +1 -0
  60. package/dist/generated/durable_actors/v1/ActivateActorRequest.d.ts +8 -0
  61. package/dist/generated/{durable_object → durable_actors}/v1/ActivateActorRequest.d.ts.map +1 -1
  62. package/dist/generated/durable_actors/v1/ActivateActorRequest.js +3 -0
  63. package/dist/generated/durable_actors/v1/ActivateActorRequest.js.map +1 -0
  64. package/dist/generated/{durable_object → durable_actors}/v1/ActorCompleted.d.ts.map +1 -1
  65. package/dist/generated/durable_actors/v1/ActorCompleted.js +3 -0
  66. package/dist/generated/durable_actors/v1/ActorCompleted.js.map +1 -0
  67. package/dist/generated/durable_actors/v1/ActorControlPlaneService.d.ts +21 -0
  68. package/dist/generated/{durable_object → durable_actors}/v1/ActorControlPlaneService.d.ts.map +1 -1
  69. package/dist/generated/durable_actors/v1/ActorControlPlaneService.js +3 -0
  70. package/dist/generated/durable_actors/v1/ActorControlPlaneService.js.map +1 -0
  71. package/dist/generated/{durable_object → durable_actors}/v1/ActorFailed.d.ts.map +1 -1
  72. package/dist/generated/durable_actors/v1/ActorFailed.js +3 -0
  73. package/dist/generated/durable_actors/v1/ActorFailed.js.map +1 -0
  74. package/dist/generated/durable_actors/v1/ActorHostService.d.ts +56 -0
  75. package/dist/generated/{durable_object → durable_actors}/v1/ActorHostService.d.ts.map +1 -1
  76. package/dist/generated/durable_actors/v1/ActorHostService.js +3 -0
  77. package/dist/generated/durable_actors/v1/ActorHostService.js.map +1 -0
  78. package/dist/generated/{durable_object → durable_actors}/v1/ActorKey.d.ts.map +1 -1
  79. package/dist/generated/durable_actors/v1/ActorKey.js +3 -0
  80. package/dist/generated/durable_actors/v1/ActorKey.js.map +1 -0
  81. package/dist/generated/{durable_object → durable_actors}/v1/ControlPlaneReply.d.ts.map +1 -1
  82. package/dist/generated/durable_actors/v1/ControlPlaneReply.js +3 -0
  83. package/dist/generated/durable_actors/v1/ControlPlaneReply.js.map +1 -0
  84. package/dist/generated/{durable_object → durable_actors}/v1/ControlPlaneRequest.d.ts.map +1 -1
  85. package/dist/generated/durable_actors/v1/ControlPlaneRequest.js +3 -0
  86. package/dist/generated/durable_actors/v1/ControlPlaneRequest.js.map +1 -0
  87. package/dist/generated/{durable_object → durable_actors}/v1/Empty.d.ts.map +1 -1
  88. package/dist/generated/durable_actors/v1/Empty.js +3 -0
  89. package/dist/generated/durable_actors/v1/Empty.js.map +1 -0
  90. package/dist/generated/durable_actors/v1/HostInvokeActorRequest.d.ts +11 -0
  91. package/dist/generated/{durable_object → durable_actors}/v1/HostInvokeActorRequest.d.ts.map +1 -1
  92. package/dist/generated/durable_actors/v1/HostInvokeActorRequest.js +3 -0
  93. package/dist/generated/durable_actors/v1/HostInvokeActorRequest.js.map +1 -0
  94. package/dist/generated/{durable_object → durable_actors}/v1/HostSocketEventRequest.d.ts +3 -3
  95. package/dist/generated/{durable_object → durable_actors}/v1/HostSocketEventRequest.d.ts.map +1 -1
  96. package/dist/generated/durable_actors/v1/HostSocketEventRequest.js +3 -0
  97. package/dist/generated/durable_actors/v1/HostSocketEventRequest.js.map +1 -0
  98. package/dist/generated/durable_actors/v1/InvokeActorReply.d.ts +16 -0
  99. package/dist/generated/{durable_object → durable_actors}/v1/InvokeActorReply.d.ts.map +1 -1
  100. package/dist/generated/durable_actors/v1/InvokeActorReply.js +3 -0
  101. package/dist/generated/durable_actors/v1/InvokeActorReply.js.map +1 -0
  102. package/dist/generated/durable_actors/v1/InvokeActorRequest.d.ts +14 -0
  103. package/dist/generated/{durable_object → durable_actors}/v1/InvokeActorRequest.d.ts.map +1 -1
  104. package/dist/generated/durable_actors/v1/InvokeActorRequest.js +3 -0
  105. package/dist/generated/durable_actors/v1/InvokeActorRequest.js.map +1 -0
  106. package/dist/generated/durable_actors/v1/PublishSocketEffectsRequest.d.ts +13 -0
  107. package/dist/generated/{durable_object → durable_actors}/v1/PublishSocketEffectsRequest.d.ts.map +1 -1
  108. package/dist/generated/durable_actors/v1/PublishSocketEffectsRequest.js +3 -0
  109. package/dist/generated/{durable_object → durable_actors}/v1/PublishSocketEffectsRequest.js.map +1 -1
  110. package/dist/generated/durable_actors/v1/ReplicaService.d.ts +42 -0
  111. package/dist/generated/{durable_object → durable_actors}/v1/ReplicaService.d.ts.map +1 -1
  112. package/dist/generated/durable_actors/v1/ReplicaService.js +3 -0
  113. package/dist/generated/durable_actors/v1/ReplicaService.js.map +1 -0
  114. package/dist/generated/durable_actors/v1/ReplicaSessionHead.d.ts +14 -0
  115. package/dist/generated/{durable_object → durable_actors}/v1/ReplicaSessionHead.d.ts.map +1 -1
  116. package/dist/generated/durable_actors/v1/ReplicaSessionHead.js +3 -0
  117. package/dist/generated/durable_actors/v1/ReplicaSessionHead.js.map +1 -0
  118. package/dist/generated/{durable_object → durable_actors}/v1/ReplicaSnapshotRef.d.ts.map +1 -1
  119. package/dist/generated/durable_actors/v1/ReplicaSnapshotRef.js +3 -0
  120. package/dist/generated/durable_actors/v1/ReplicaSnapshotRef.js.map +1 -0
  121. package/dist/generated/durable_actors/v1/ReplicaStreamHead.d.ts +11 -0
  122. package/dist/generated/{durable_object → durable_actors}/v1/ReplicaStreamHead.d.ts.map +1 -1
  123. package/dist/generated/durable_actors/v1/ReplicaStreamHead.js +3 -0
  124. package/dist/generated/durable_actors/v1/ReplicaStreamHead.js.map +1 -0
  125. package/dist/generated/{durable_object → durable_actors}/v1/ReplicaStreamIdentity.d.ts.map +1 -1
  126. package/dist/generated/durable_actors/v1/ReplicaStreamIdentity.js +3 -0
  127. package/dist/generated/durable_actors/v1/ReplicaStreamIdentity.js.map +1 -0
  128. package/dist/generated/{durable_object → durable_actors}/v1/Reroute.d.ts.map +1 -1
  129. package/dist/generated/durable_actors/v1/Reroute.js +3 -0
  130. package/dist/generated/durable_actors/v1/Reroute.js.map +1 -0
  131. package/dist/generated/{durable_object → durable_actors}/v1/SnapshotData.d.ts.map +1 -1
  132. package/dist/generated/durable_actors/v1/SnapshotData.js +3 -0
  133. package/dist/generated/durable_actors/v1/SnapshotData.js.map +1 -0
  134. package/dist/generated/durable_actors/v1/SnapshotService.d.ts +32 -0
  135. package/dist/generated/{durable_object → durable_actors}/v1/SnapshotService.d.ts.map +1 -1
  136. package/dist/generated/durable_actors/v1/SnapshotService.js +3 -0
  137. package/dist/generated/durable_actors/v1/SnapshotService.js.map +1 -0
  138. package/dist/generated/{durable_object → durable_actors}/v1/SnapshotWriteReply.d.ts.map +1 -1
  139. package/dist/generated/durable_actors/v1/SnapshotWriteReply.js +3 -0
  140. package/dist/generated/durable_actors/v1/SnapshotWriteReply.js.map +1 -0
  141. package/dist/generated/durable_actors.d.ts +69 -0
  142. package/dist/generated/{durable_object.d.ts.map → durable_actors.d.ts.map} +1 -1
  143. package/dist/generated/durable_actors.js +2 -0
  144. package/dist/generated/durable_actors.js.map +1 -0
  145. package/dist/generated/{durable_object.proto → durable_actors.proto} +1 -1
  146. package/dist/host/actor-worker.js +1 -1
  147. package/dist/host/actor-worker.js.map +1 -1
  148. package/dist/host.d.ts +1 -1
  149. package/dist/host.d.ts.map +1 -1
  150. package/dist/host.js +1 -1
  151. package/dist/host.js.map +1 -1
  152. package/dist/index.d.ts +1 -0
  153. package/dist/index.d.ts.map +1 -1
  154. package/dist/index.js +1 -0
  155. package/dist/index.js.map +1 -1
  156. package/dist/localRuntime.d.ts +9 -1
  157. package/dist/localRuntime.d.ts.map +1 -1
  158. package/dist/localRuntime.js +2 -1
  159. package/dist/localRuntime.js.map +1 -1
  160. package/dist/proxy.d.ts +10 -1
  161. package/dist/proxy.d.ts.map +1 -1
  162. package/dist/proxy.js +8 -3
  163. package/dist/proxy.js.map +1 -1
  164. package/dist/templates/actor/README.md +4 -4
  165. package/dist/templates/actor/package.json +1 -2
  166. package/dist/templates/ai-chat/.env.example +6 -0
  167. package/dist/templates/ai-chat/README.md +44 -16
  168. package/dist/templates/ai-chat/gitignore +0 -1
  169. package/dist/templates/ai-chat/package.json +2 -1
  170. package/dist/templates/ai-chat/src/actors.ts +20 -0
  171. package/dist/templates/ai-chat/src/backend.ts +18 -5
  172. package/dist/templates/ai-chat/tsconfig.json +1 -1
  173. package/dist/templates/chat/.env.example +6 -0
  174. package/dist/templates/chat/README.md +57 -12
  175. package/dist/templates/chat/gitignore +0 -1
  176. package/dist/templates/chat/package.json +4 -3
  177. package/dist/templates/chat/src/backend.ts +5 -2
  178. package/dist/templates/documents/.env.example +6 -0
  179. package/dist/templates/documents/README.md +32 -17
  180. package/dist/templates/documents/gitignore +0 -1
  181. package/dist/templates/documents/package.json +4 -3
  182. package/dist/templates/documents/src/backend.ts +5 -2
  183. package/package.json +10 -7
  184. package/dist/cli/deploy.d.ts +0 -4
  185. package/dist/cli/deploy.d.ts.map +0 -1
  186. package/dist/cli/deploy.js +0 -39
  187. package/dist/cli/deploy.js.map +0 -1
  188. package/dist/cli/objects.d.ts +0 -4
  189. package/dist/cli/objects.d.ts.map +0 -1
  190. package/dist/cli/objects.js +0 -68
  191. package/dist/cli/objects.js.map +0 -1
  192. package/dist/generated/durable_object/v1/ActivateActorReply.js +0 -3
  193. package/dist/generated/durable_object/v1/ActivateActorReply.js.map +0 -1
  194. package/dist/generated/durable_object/v1/ActivateActorRequest.d.ts +0 -8
  195. package/dist/generated/durable_object/v1/ActivateActorRequest.js +0 -3
  196. package/dist/generated/durable_object/v1/ActivateActorRequest.js.map +0 -1
  197. package/dist/generated/durable_object/v1/ActorCompleted.js +0 -3
  198. package/dist/generated/durable_object/v1/ActorCompleted.js.map +0 -1
  199. package/dist/generated/durable_object/v1/ActorControlPlaneService.d.ts +0 -21
  200. package/dist/generated/durable_object/v1/ActorControlPlaneService.js +0 -3
  201. package/dist/generated/durable_object/v1/ActorControlPlaneService.js.map +0 -1
  202. package/dist/generated/durable_object/v1/ActorFailed.js +0 -3
  203. package/dist/generated/durable_object/v1/ActorFailed.js.map +0 -1
  204. package/dist/generated/durable_object/v1/ActorHostService.d.ts +0 -56
  205. package/dist/generated/durable_object/v1/ActorHostService.js +0 -3
  206. package/dist/generated/durable_object/v1/ActorHostService.js.map +0 -1
  207. package/dist/generated/durable_object/v1/ActorKey.js +0 -3
  208. package/dist/generated/durable_object/v1/ActorKey.js.map +0 -1
  209. package/dist/generated/durable_object/v1/ControlPlaneReply.js +0 -3
  210. package/dist/generated/durable_object/v1/ControlPlaneReply.js.map +0 -1
  211. package/dist/generated/durable_object/v1/ControlPlaneRequest.js +0 -3
  212. package/dist/generated/durable_object/v1/ControlPlaneRequest.js.map +0 -1
  213. package/dist/generated/durable_object/v1/Empty.js +0 -3
  214. package/dist/generated/durable_object/v1/Empty.js.map +0 -1
  215. package/dist/generated/durable_object/v1/HostInvokeActorRequest.d.ts +0 -11
  216. package/dist/generated/durable_object/v1/HostInvokeActorRequest.js +0 -3
  217. package/dist/generated/durable_object/v1/HostInvokeActorRequest.js.map +0 -1
  218. package/dist/generated/durable_object/v1/HostSocketEventRequest.js +0 -3
  219. package/dist/generated/durable_object/v1/HostSocketEventRequest.js.map +0 -1
  220. package/dist/generated/durable_object/v1/InvokeActorReply.d.ts +0 -16
  221. package/dist/generated/durable_object/v1/InvokeActorReply.js +0 -3
  222. package/dist/generated/durable_object/v1/InvokeActorReply.js.map +0 -1
  223. package/dist/generated/durable_object/v1/InvokeActorRequest.d.ts +0 -14
  224. package/dist/generated/durable_object/v1/InvokeActorRequest.js +0 -3
  225. package/dist/generated/durable_object/v1/InvokeActorRequest.js.map +0 -1
  226. package/dist/generated/durable_object/v1/PublishSocketEffectsRequest.d.ts +0 -13
  227. package/dist/generated/durable_object/v1/PublishSocketEffectsRequest.js +0 -3
  228. package/dist/generated/durable_object/v1/ReplicaService.d.ts +0 -42
  229. package/dist/generated/durable_object/v1/ReplicaService.js +0 -3
  230. package/dist/generated/durable_object/v1/ReplicaService.js.map +0 -1
  231. package/dist/generated/durable_object/v1/ReplicaSessionHead.d.ts +0 -14
  232. package/dist/generated/durable_object/v1/ReplicaSessionHead.js +0 -3
  233. package/dist/generated/durable_object/v1/ReplicaSessionHead.js.map +0 -1
  234. package/dist/generated/durable_object/v1/ReplicaSnapshotRef.js +0 -3
  235. package/dist/generated/durable_object/v1/ReplicaSnapshotRef.js.map +0 -1
  236. package/dist/generated/durable_object/v1/ReplicaStreamHead.d.ts +0 -11
  237. package/dist/generated/durable_object/v1/ReplicaStreamHead.js +0 -3
  238. package/dist/generated/durable_object/v1/ReplicaStreamHead.js.map +0 -1
  239. package/dist/generated/durable_object/v1/ReplicaStreamIdentity.js +0 -3
  240. package/dist/generated/durable_object/v1/ReplicaStreamIdentity.js.map +0 -1
  241. package/dist/generated/durable_object/v1/Reroute.js +0 -3
  242. package/dist/generated/durable_object/v1/Reroute.js.map +0 -1
  243. package/dist/generated/durable_object/v1/SnapshotData.js +0 -3
  244. package/dist/generated/durable_object/v1/SnapshotData.js.map +0 -1
  245. package/dist/generated/durable_object/v1/SnapshotService.d.ts +0 -32
  246. package/dist/generated/durable_object/v1/SnapshotService.js +0 -3
  247. package/dist/generated/durable_object/v1/SnapshotService.js.map +0 -1
  248. package/dist/generated/durable_object/v1/SnapshotWriteReply.js +0 -3
  249. package/dist/generated/durable_object/v1/SnapshotWriteReply.js.map +0 -1
  250. package/dist/generated/durable_object.d.ts +0 -69
  251. package/dist/generated/durable_object.js +0 -2
  252. package/dist/generated/durable_object.js.map +0 -1
  253. package/dist/templates/ai-chat/src/durable-objects.ts +0 -15
  254. /package/dist/generated/{durable_object → durable_actors}/v1/ActivateActorReply.d.ts +0 -0
  255. /package/dist/generated/{durable_object → durable_actors}/v1/ActorCompleted.d.ts +0 -0
  256. /package/dist/generated/{durable_object → durable_actors}/v1/ActorFailed.d.ts +0 -0
  257. /package/dist/generated/{durable_object → durable_actors}/v1/ActorKey.d.ts +0 -0
  258. /package/dist/generated/{durable_object → durable_actors}/v1/ControlPlaneReply.d.ts +0 -0
  259. /package/dist/generated/{durable_object → durable_actors}/v1/ControlPlaneRequest.d.ts +0 -0
  260. /package/dist/generated/{durable_object → durable_actors}/v1/Empty.d.ts +0 -0
  261. /package/dist/generated/{durable_object → durable_actors}/v1/ReplicaSnapshotRef.d.ts +0 -0
  262. /package/dist/generated/{durable_object → durable_actors}/v1/ReplicaStreamIdentity.d.ts +0 -0
  263. /package/dist/generated/{durable_object → durable_actors}/v1/Reroute.d.ts +0 -0
  264. /package/dist/generated/{durable_object → durable_actors}/v1/SnapshotData.d.ts +0 -0
  265. /package/dist/generated/{durable_object → durable_actors}/v1/SnapshotWriteReply.d.ts +0 -0
  266. /package/dist/templates/actor/src/{durable-objects.ts → actors.ts} +0 -0
  267. /package/dist/templates/chat/src/{durable-objects.ts → actors.ts} +0 -0
  268. /package/dist/templates/documents/src/{durable-objects.ts → actors.ts} +0 -0
@@ -7,11 +7,10 @@
7
7
  },
8
8
  "scripts": {
9
9
  "dev": "durable-actors dev",
10
- "build": "durable-actors build",
11
10
  "check": "tsc --noEmit"
12
11
  },
13
12
  "dependencies": {
14
- "durable-actors": "0.2.5"
13
+ "durable-actors": "0.2.7"
15
14
  },
16
15
  "devDependencies": {
17
16
  "@types/node": "^22.0.0",
@@ -1 +1,7 @@
1
+ DURABLE_ACTORS_PROJECT_ID=ai-chat-example
2
+ DURABLE_ACTORS_SECRET=local-ai-chat-example
3
+ DURABLE_ACTORS_CONTROL_PLANE_URL=http://127.0.0.1:7100
4
+ DURABLE_ACTORS_PORT=7100
5
+ DURABLE_ACTORS_BINARY=
6
+ PORT=3000
1
7
  OPENAI_API_KEY=
@@ -1,41 +1,69 @@
1
- # AI chat with durable history
1
+ # AI chat
2
2
 
3
- Requires Node.js 20+ and Bun 1.4.2+ on your PATH; Bun executes the actors.
3
+ An Express + React app that streams replies with the Vercel AI SDK and saves conversations in durable actors.
4
4
 
5
- Vercel AI SDK streams replies; a durable actor stores the conversation.
5
+ ## Run locally
6
6
 
7
- ## Run it
7
+ Requires Node.js 22.19+, Bun 1.4.2+, and an OpenAI API key.
8
8
 
9
9
  ```sh
10
10
  npx durable-actors init ai-chat-example --template ai-chat
11
11
  cd ai-chat-example
12
12
  npm install
13
+ cp .env.example .env
13
14
  ```
14
15
 
15
- Copy `.env.example` to `.env` and add your `OPENAI_API_KEY`, then start the actors:
16
+ Already in the example directory? Start at `npm install`. Add `OPENAI_API_KEY` to `.env`, then start the actors:
16
17
 
17
18
  ```sh
18
- npx durable-actors dev
19
+ npm run dev:actors
19
20
  ```
20
21
 
21
- Wait for `Local actors ready`. In another terminal, run the printed export command, then:
22
+ Wait for `Ready`. In another terminal in the same directory:
22
23
 
23
24
  ```sh
24
25
  npm run dev
25
26
  ```
26
27
 
27
- Open [the chat](http://127.0.0.1:3000), send a message, and reload after the reply finishes. Your history is restored from the actor, including after restarting the servers.
28
+ Open [localhost:3000](http://127.0.0.1:3000), send a message, and reload after the reply finishes. The conversation survives server restarts.
28
29
 
29
- If you already have this directory, start at `npm install`. No client generation is needed for this example.
30
+ ## Save the conversation
30
31
 
31
- ## The code
32
+ [ChatHistory](src/actors.ts) keeps one conversation per actor ID:
32
33
 
33
- - [src/durable-objects.ts](src/durable-objects.ts) stores AI SDK messages in a private `@Persisted` field. Each chat ID gets its own actor.
34
- - [src/backend.ts](src/backend.ts) loads saved history, appends the new user message, streams a reply, and saves the completed assistant message.
35
- - [src/Chat.tsx](src/Chat.tsx) loads the lobby history and uses `useChat` to send messages and render streaming replies.
34
+ ```ts
35
+ import { Actor, Persisted } from "durable-actors"
36
36
 
37
- For a remote actor server, use the [connection overrides](../../docs/reference/configuration.md) on the backend.
37
+ export class ChatHistory extends Actor {
38
+ @Persisted private messages: ChatMessage[] = []
38
39
 
39
- This sample has one shared lobby and no authentication. Authenticate both routes and check chat ownership before using it for private conversations. Reloads restore saved messages; in-progress streams are not resumed.
40
+ async load() {
41
+ return this.messages
42
+ }
40
43
 
41
- See Vercel’s [message persistence guide](https://ai-sdk.dev/docs/ai-sdk-ui/chatbot-message-persistence) for the AI SDK flow.
44
+ async append(message: ChatMessage) {
45
+ this.messages.push(message)
46
+ return this.messages
47
+ }
48
+ }
49
+
50
+ export type ChatMessage = {
51
+ id: string
52
+ role: "system" | "user" | "assistant"
53
+ parts: { type: "text"; text: string }[]
54
+ }
55
+ ```
56
+
57
+ ## Stream the reply
58
+
59
+ The [Express backend](src/backend.ts) appends the user message, sends the saved conversation to the model, and streams the reply. It saves the assistant message when the reply completes.
60
+
61
+ The [React client](src/Chat.tsx) loads saved messages and uses `useChat` to display the stream. This demo saves text only; in-progress streams are not resumed after a reload.
62
+
63
+ The lobby is shared and has no authentication. Add authentication and chat ownership checks before using it for private conversations.
64
+
65
+ ## Development
66
+
67
+ Both processes read `.env`; actor state lives in `.durable-actors/`. Actor code reloads automatically; restart `npm run dev` after editing the actor class imported by the backend. For multiple examples, set distinct `PORT`, `DURABLE_ACTORS_PORT`, and matching control-plane URLs; see [Run the examples together](../README.md).
68
+
69
+ `npm run build` checks TypeScript and builds the frontend.
@@ -2,7 +2,6 @@ node_modules/
2
2
  dist/
3
3
  generated/
4
4
  .durable-actors/
5
- .little-actors/
6
5
  .env
7
6
  .env.*
8
7
  !.env.example
@@ -7,6 +7,7 @@
7
7
  },
8
8
  "scripts": {
9
9
  "dev": "tsx --env-file=.env src/backend.ts",
10
+ "dev:actors": "durable-actors dev",
10
11
  "build": "tsc --noEmit && vite build"
11
12
  },
12
13
  "dependencies": {
@@ -14,7 +15,7 @@
14
15
  "@ai-sdk/react": "^4.0.100",
15
16
  "ai": "^7.0.97",
16
17
  "express": "^5.2.1",
17
- "durable-actors": "0.2.5",
18
+ "durable-actors": "0.2.7",
18
19
  "react": "^19.3.0",
19
20
  "react-dom": "^19.3.0"
20
21
  },
@@ -0,0 +1,20 @@
1
+ import { Actor, Persisted } from "durable-actors"
2
+
3
+ export class ChatHistory extends Actor {
4
+ @Persisted private messages: ChatMessage[] = []
5
+
6
+ async load() {
7
+ return this.messages
8
+ }
9
+
10
+ async append(message: ChatMessage) {
11
+ this.messages.push(message)
12
+ return this.messages
13
+ }
14
+ }
15
+
16
+ export type ChatMessage = {
17
+ id: string
18
+ role: "system" | "user" | "assistant"
19
+ parts: { type: "text"; text: string }[]
20
+ }
@@ -1,11 +1,16 @@
1
1
  import { openai } from "@ai-sdk/openai"
2
2
  import { convertToModelMessages, generateId, pipeUIMessageStreamToResponse, streamText, toUIMessageStream, validateUIMessages } from "ai"
3
+ import type { UIMessage } from "ai"
3
4
  import express from "express"
5
+ import { createServer as createHttpServer } from "node:http"
4
6
  import { createServer } from "vite"
5
7
 
6
- import { ChatHistory } from "./durable-objects.js"
8
+ import { ChatHistory } from "./actors.js"
9
+ import type { ChatMessage } from "./actors.js"
7
10
 
8
11
  const app = express()
12
+ const server = createHttpServer(app)
13
+ const port = Number(process.env.PORT ?? 3000)
9
14
  app.use(express.json())
10
15
 
11
16
  app.get("/api/chat/:id", async (request, response) => {
@@ -16,7 +21,7 @@ app.post("/api/chat", async (request, response) => {
16
21
  const [message] = await validateUIMessages({ messages: [request.body.messages.at(-1)] })
17
22
  if (message.role !== "user") return response.sendStatus(400)
18
23
  const chat = ChatHistory.get(request.body.id)
19
- const messages = await chat.append(message)
24
+ const messages = await chat.append(historyMessage(message))
20
25
  const result = streamText({
21
26
  model: openai("gpt-5-mini"),
22
27
  messages: await convertToModelMessages(messages)
@@ -28,14 +33,22 @@ app.post("/api/chat", async (request, response) => {
28
33
  originalMessages: messages,
29
34
  generateMessageId: generateId,
30
35
  onEnd: async ({ responseMessage, outcome }) => {
31
- if (outcome.status === "completed") await chat.append(responseMessage)
36
+ if (outcome.status === "completed") await chat.append(historyMessage(responseMessage))
32
37
  }
33
38
  })
34
39
  })
35
40
  })
36
41
 
37
42
  const vite = await createServer({
38
- server: { middlewareMode: true, fs: { deny: [".env", ".env.*", "**/.durable-actors/**", "**/.little-actors/**", "**/.git/**"] } }
43
+ server: { middlewareMode: true, hmr: { server }, fs: { deny: [".env", ".env.*", "**/.durable-actors/**", "**/.git/**"] } }
39
44
  })
40
45
  app.use(vite.middlewares)
41
- app.listen(3000, "127.0.0.1", () => console.log("AI chat: http://127.0.0.1:3000"))
46
+ server.listen(port, "127.0.0.1", () => console.log(`AI chat: http://127.0.0.1:${port}`))
47
+
48
+ function historyMessage(message: UIMessage): ChatMessage {
49
+ return {
50
+ id: message.id,
51
+ role: message.role,
52
+ parts: message.parts.filter(part => part.type === "text").map(part => ({ type: "text", text: part.text }))
53
+ }
54
+ }
@@ -9,5 +9,5 @@
9
9
  "noEmit": true,
10
10
  "types": ["node"]
11
11
  },
12
- "include": ["src", "generated"]
12
+ "include": ["src"]
13
13
  }
@@ -0,0 +1,6 @@
1
+ DURABLE_ACTORS_PROJECT_ID=chat-example
2
+ DURABLE_ACTORS_SECRET=local-chat-example
3
+ DURABLE_ACTORS_CONTROL_PLANE_URL=http://127.0.0.1:7100
4
+ DURABLE_ACTORS_PORT=7100
5
+ DURABLE_ACTORS_BINARY=
6
+ PORT=3000
@@ -1,29 +1,74 @@
1
- # Express + React chat
1
+ # Chatroom
2
2
 
3
- Requires Node.js 20+ and Bun 1.4.2+ on your PATH; Bun executes the actors.
3
+ An Express + React chatroom backed by a durable actor. Messages appear in every connected tab, and history survives server restarts.
4
4
 
5
- Create this sample with `npx durable-actors init chat-example --template chat`.
5
+ ## Run locally
6
6
 
7
- ## Run it
7
+ Requires Node.js 22.19+ and Bun 1.4.2+.
8
8
 
9
9
  ```sh
10
+ npx durable-actors init chat-example --template chat
11
+ cd chat-example
10
12
  npm install
11
- npx durable-actors generate
12
- npx durable-actors dev
13
+ cp .env.example .env
14
+ npm run dev:actors
13
15
  ```
14
16
 
15
- Wait for `Local actors ready`. In another terminal, run the printed export command, then:
17
+ Already in the example directory? Start at `npm install`.
18
+
19
+ Wait for `Ready`. In another terminal in the same directory:
16
20
 
17
21
  ```sh
18
22
  npm run dev
19
23
  ```
20
24
 
21
- Open [the chat](http://127.0.0.1:3000) in two tabs. Send a message, then reload to see the saved history.
25
+ Open [localhost:3000](http://127.0.0.1:3000) in two tabs. Send a message, then restart the actor server and reload to see the saved history.
26
+
27
+ ## Define the actor
28
+
29
+ [ChatRoom](src/actors.ts) saves messages and sends the updated history to everyone in the room:
30
+
31
+ ```ts
32
+ import { Actor, Persisted } from "durable-actors"
33
+ import type { ActorSocket } from "durable-actors"
34
+
35
+ export class ChatRoom extends Actor<Member, string, ChatMessage[]> {
36
+ @Persisted history: ChatMessage[] = []
37
+
38
+ async onConnect(socket: ActorSocket<Member, ChatMessage[]>) {
39
+ socket.send(this.history)
40
+ }
41
+
42
+ async onMessage(socket: ActorSocket<Member, ChatMessage[]>, text: string) {
43
+ this.history.push({ name: socket.metadata.name, text })
44
+ this.broadcast(this.history)
45
+ }
46
+ }
47
+
48
+ type Member = { name: string }
49
+ type ChatMessage = { name: string; text: string }
50
+ ```
51
+
52
+ Each room ID has its own history.
53
+
54
+ ## Connect the app
55
+
56
+ The [Express backend](src/backend.ts) issues a WebSocket URL with `actors.ChatRoom.prepareWebsocket`. The [React client](src/Chat.tsx) connects and sends JSON messages:
57
+
58
+ ```js
59
+ const response = await fetch("/api/socket/ChatRoom/lobby", { method: "POST" })
60
+ if (!response.ok) throw new Error("Connection denied")
61
+ const { websocketUrl } = await response.json()
62
+ const socket = new WebSocket(websocketUrl)
63
+
64
+ socket.onopen = () => socket.send(JSON.stringify("Hello"))
65
+ socket.onmessage = event => console.log(JSON.parse(event.data))
66
+ ```
22
67
 
23
- ## How it works
68
+ Everyone joins as a guest. Add authentication and room access checks before issuing URLs in your app. Reload to reconnect after a disconnect.
24
69
 
25
- Everyone is a guest in this demo. In your app, authenticate the request before `actors.ChatRoom.prepareWebsocket` and derive metadata from the signed-in user.
70
+ ## Development
26
71
 
27
- The frontend fetches a signed URL from the backend and passes it to `new WebSocket()`. The actor sends history explicitly on connection and after each message. Reload to reconnect if the socket closes.
72
+ Both processes read `.env`; saved state lives in `.durable-actors/`. Actor code reloads automatically. After changing public actor types, restart `npm run dev` to regenerate the client. For multiple examples, set distinct `PORT`, `DURABLE_ACTORS_PORT`, and matching control-plane URLs; see [Run the examples together](../README.md).
28
73
 
29
- After changing the actor's types, rerun `npx durable-actors generate` and restart the actor server.
74
+ `npm run build` generates clients, checks TypeScript, and builds the frontend.
@@ -2,7 +2,6 @@ node_modules/
2
2
  dist/
3
3
  generated/
4
4
  .durable-actors/
5
- .little-actors/
6
5
  .env
7
6
  .env.*
8
7
  !.env.example
@@ -6,12 +6,13 @@
6
6
  "node": ">=22.19.0"
7
7
  },
8
8
  "scripts": {
9
- "dev": "tsx src/backend.ts",
10
- "build": "tsc --noEmit && vite build"
9
+ "dev": "durable-actors generate && tsx --env-file=.env src/backend.ts",
10
+ "dev:actors": "durable-actors dev",
11
+ "build": "durable-actors generate && tsc --noEmit && vite build"
11
12
  },
12
13
  "dependencies": {
13
14
  "express": "^5.2.1",
14
- "durable-actors": "0.2.5",
15
+ "durable-actors": "0.2.7",
15
16
  "react": "^19.3.0",
16
17
  "react-dom": "^19.3.0"
17
18
  },
@@ -1,9 +1,12 @@
1
1
  import express from "express"
2
+ import { createServer as createHttpServer } from "node:http"
2
3
  import { createServer } from "vite"
3
4
 
4
5
  import { actors } from "../generated/index.js"
5
6
 
6
7
  const app = express()
8
+ const server = createHttpServer(app)
9
+ const port = Number(process.env.PORT ?? 3000)
7
10
 
8
11
  app.post("/api/socket/ChatRoom/:actorId", async (request, response) => {
9
12
  const grant = await actors.ChatRoom.prepareWebsocket({
@@ -14,7 +17,7 @@ app.post("/api/socket/ChatRoom/:actorId", async (request, response) => {
14
17
  })
15
18
 
16
19
  const vite = await createServer({
17
- server: { middlewareMode: true, fs: { deny: [".env", ".env.*", "**/.durable-actors/**", "**/.little-actors/**", "**/.git/**"] } }
20
+ server: { middlewareMode: true, hmr: { server }, fs: { deny: [".env", ".env.*", "**/.durable-actors/**", "**/.git/**"] } }
18
21
  })
19
22
  app.use(vite.middlewares)
20
- app.listen(3000, "127.0.0.1", () => console.log("Chat: http://127.0.0.1:3000"))
23
+ server.listen(port, "127.0.0.1", () => console.log(`Chat: http://127.0.0.1:${port}`))
@@ -0,0 +1,6 @@
1
+ DURABLE_ACTORS_PROJECT_ID=documents-example
2
+ DURABLE_ACTORS_SECRET=local-documents-example
3
+ DURABLE_ACTORS_CONTROL_PLANE_URL=http://127.0.0.1:7100
4
+ DURABLE_ACTORS_PORT=7100
5
+ DURABLE_ACTORS_BINARY=
6
+ PORT=3000
@@ -1,38 +1,53 @@
1
- # Shared documents
1
+ # Collaborative documents
2
2
 
3
- Requires Node.js 20+ and Bun 1.4.2+ on your PATH; Bun executes the actors.
3
+ A Tiptap editor with Yjs for concurrent edits and durable actors for saved documents. Edit together in multiple tabs, then reload to pick up where you left off.
4
4
 
5
- A small Tiptap editor with Yjs for concurrent edits and durable actors for saved documents.
5
+ ## Run locally
6
6
 
7
- ## Run it
7
+ Requires Node.js 22.19+ and Bun 1.4.2+.
8
8
 
9
9
  ```sh
10
10
  npx durable-actors init documents-example --template documents
11
11
  cd documents-example
12
12
  npm install
13
- npx durable-actors generate
14
- npx durable-actors dev
13
+ cp .env.example .env
14
+ npm run dev:actors
15
15
  ```
16
16
 
17
- Wait for `Local actors ready`. In another terminal, run the printed export command, then:
17
+ Already in the example directory? Start at `npm install`.
18
+
19
+ Wait for `Ready`. In another terminal in the same directory:
18
20
 
19
21
  ```sh
20
22
  npm run dev
21
23
  ```
22
24
 
23
- Open [the editor](http://127.0.0.1:3000) in two tabs. Type in Welcome, format some text, and edit from both tabs. Add another document and switch between them. Reload after changes arrive in the other tab to see the saved content.
25
+ Open [localhost:3000](http://127.0.0.1:3000) in two tabs. Edit **Welcome** from both, add another document, and switch between them. Restart the servers and reload to restore saved documents.
26
+
27
+ ## Save and share documents
28
+
29
+ [src/actors.ts](src/actors.ts) defines two actors:
30
+
31
+ - `Workspace` saves the document list.
32
+ - `Document` merges Yjs updates, saves the merged content, and broadcasts it to connected editors. Each document ID has its own actor.
24
33
 
25
- If you already have this directory, start at `npm install`. No external service is needed.
34
+ A document joins through the [Express backend](src/backend.ts):
35
+
36
+ ```ts
37
+ import { actors } from "../generated/index.js"
38
+
39
+ const grant = await actors.Document.prepareWebsocket({
40
+ actorId: "welcome",
41
+ metadata: null
42
+ })
43
+ ```
26
44
 
27
- ## The code
45
+ The [collaboration client](src/collaboration.ts) opens the returned `websocketUrl` and exchanges Yjs updates. [App.tsx](src/App.tsx) handles document navigation; [Editor.tsx](src/Editor.tsx) connects Tiptap to the shared document.
28
46
 
29
- - [src/durable-objects.ts](src/durable-objects.ts): a workspace actor stores the document list; one document actor per ID merges and saves Yjs state. The actors send initial data in `onConnect` and broadcast updates explicitly.
30
- - [src/backend.ts](src/backend.ts): issues WebSocket credentials using the generated `prepareWebsocket` helpers and local defaults.
31
- - [src/collaboration.ts](src/collaboration.ts): connects Yjs to a native WebSocket. It sends local updates and applies remote state without echoing it.
32
- - [src/App.tsx](src/App.tsx) and [src/Editor.tsx](src/Editor.tsx): document navigation and Tiptap’s editor, formatting controls, and collaborative undo/redo.
47
+ Editing pauses while disconnected. Reload to reconnect; unsaved edits are not stored in the browser. This demo shares one workspace without authentication. Add user authentication and document access checks before issuing WebSocket URLs in your app.
33
48
 
34
- Yjs updates are encoded as base64 strings to fit the SDK’s JSON protocol. The actor saves the Yjs state, preserving the information needed to merge concurrent edits. Clients receive the complete merged document after each edit; this keeps the sample small rather than optimizing for large documents.
49
+ ## Development
35
50
 
36
- Editing pauses while disconnected. Reload to request a fresh connection. There is no automatic reconnect or browser storage for unsaved edits. Keep `.durable-actors/` and restart both servers to restore saved documents.
51
+ Both processes read `.env`; saved state lives in `.durable-actors/`. Actor code reloads automatically. After changing public actor types, restart `npm run dev` to regenerate the client. For multiple examples, set distinct `PORT`, `DURABLE_ACTORS_PORT`, and matching control-plane URLs; see [Run the examples together](../README.md).
37
52
 
38
- This demo has one shared workspace and no authentication. In an application, authenticate the proxy route and authorize access to the requested workspace or document. Presence cursors, document deletion, and permissions UI are left out.
53
+ `npm run build` generates clients, checks TypeScript, and builds the frontend.
@@ -2,7 +2,6 @@ node_modules/
2
2
  dist/
3
3
  generated/
4
4
  .durable-actors/
5
- .little-actors/
6
5
  .env
7
6
  .env.*
8
7
  !.env.example
@@ -6,8 +6,9 @@
6
6
  "node": ">=22.19.0"
7
7
  },
8
8
  "scripts": {
9
- "dev": "tsx src/backend.ts",
10
- "build": "tsc --noEmit && vite build"
9
+ "dev": "durable-actors generate && tsx --env-file=.env src/backend.ts",
10
+ "dev:actors": "durable-actors dev",
11
+ "build": "durable-actors generate && tsc --noEmit && vite build"
11
12
  },
12
13
  "dependencies": {
13
14
  "@tiptap/core": "^3.31.3",
@@ -18,7 +19,7 @@
18
19
  "@tiptap/y-tiptap": "^3.0.7",
19
20
  "express": "^5.2.1",
20
21
  "lib0": "^0.2.117",
21
- "durable-actors": "0.2.5",
22
+ "durable-actors": "0.2.7",
22
23
  "react": "^19.3.0",
23
24
  "react-dom": "^19.3.0",
24
25
  "yjs": "^13.6.32"
@@ -1,9 +1,12 @@
1
1
  import express from "express"
2
+ import { createServer as createHttpServer } from "node:http"
2
3
  import { createServer } from "vite"
3
4
 
4
5
  import { actors } from "../generated/index.js"
5
6
 
6
7
  const app = express()
8
+ const server = createHttpServer(app)
9
+ const port = Number(process.env.PORT ?? 3000)
7
10
 
8
11
  app.post("/api/socket/:actorName/:actorId", async (request, response) => {
9
12
  const { actorName, actorId } = request.params
@@ -12,7 +15,7 @@ app.post("/api/socket/:actorName/:actorId", async (request, response) => {
12
15
  })
13
16
 
14
17
  const vite = await createServer({
15
- server: { middlewareMode: true, fs: { deny: [".env", ".env.*", "**/.durable-actors/**", "**/.little-actors/**", "**/.git/**"] } }
18
+ server: { middlewareMode: true, hmr: { server }, fs: { deny: [".env", ".env.*", "**/.durable-actors/**", "**/.git/**"] } }
16
19
  })
17
20
  app.use(vite.middlewares)
18
- app.listen(3000, "127.0.0.1", () => console.log("Documents: http://127.0.0.1:3000"))
21
+ server.listen(port, "127.0.0.1", () => console.log(`Documents: http://127.0.0.1:${port}`))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "durable-actors",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "Provider-neutral actors for sandbox compute",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -11,7 +11,7 @@
11
11
  "keywords": [
12
12
  "actors",
13
13
  "distributed-systems",
14
- "durable-objects",
14
+ "durable-actors",
15
15
  "modal",
16
16
  "serverless"
17
17
  ],
@@ -95,17 +95,20 @@
95
95
  },
96
96
  "devDependencies": {
97
97
  "@types/node": "^22.0.0",
98
- "@types/ws": "^8.18.1"
98
+ "@types/ws": "^8.18.1",
99
+ "typedoc": "^0.28.20",
100
+ "typedoc-plugin-missing-exports": "^4.1.4"
99
101
  },
100
102
  "scripts": {
101
- "build": "pnpm run build:observer && pnpm run generate:proto && tsc -p tsconfig.build.json && cp ../proto/durable_object.proto dist/generated/durable_object.proto && node scripts/build-template.mjs",
102
- "generate:proto": "proto-loader-gen-types --longs=Number --defaults --oneofs --grpcLib=@grpc/grpc-js --importFileExtension=.js --outDir=src/generated ../proto/durable_object.proto",
103
+ "build": "pnpm run build:observer && pnpm run generate:proto && tsc -p tsconfig.build.json && cp ../proto/durable_actors.proto dist/generated/durable_actors.proto && node scripts/build-template.mjs && pnpm --dir .. install --offline --frozen-lockfile --ignore-scripts",
104
+ "generate:proto": "rm -rf src/generated && proto-loader-gen-types --longs=Number --defaults --oneofs --grpcLib=@grpc/grpc-js --importFileExtension=.js --outDir=src/generated ../proto/durable_actors.proto",
103
105
  "check": "pnpm run format:check && pnpm run test && pnpm run package:check",
104
106
  "clean": "rm -rf dist .test-dist",
105
107
  "package:check": "node --test tests/scripts/codegen-api.test.mjs tests/scripts/build-artifact.test.mjs",
106
- "test": "pnpm run clean && pnpm run build && node tests/prepare.mjs && tsc -p tsconfig.test.json && cp dist/generated/durable_object.proto .test-dist/src/generated/durable_object.proto && node scripts/test.mjs",
108
+ "test": "pnpm run clean && pnpm run build && node tests/prepare.mjs && tsc -p tsconfig.test.json && cp dist/generated/durable_actors.proto .test-dist/src/generated/durable_actors.proto && node scripts/test.mjs",
107
109
  "format": "prettier --config ../.prettierrc --write \"src/**/*.ts\" \"tests/**/*.ts\" \"scripts/*.mjs\" \"tests/**/*.mjs\"",
108
110
  "format:check": "prettier --config ../.prettierrc --check \"src/**/*.ts\" \"tests/**/*.ts\" \"scripts/*.mjs\" \"tests/**/*.mjs\"",
109
- "build:observer": "pnpm --filter durable-actors-observer build"
111
+ "build:observer": "pnpm --filter durable-actors-observer build",
112
+ "docs": "typedoc --options typedoc.json"
110
113
  }
111
114
  }
@@ -1,4 +0,0 @@
1
- import { Command } from "commander";
2
- declare function registerDeployCommand(program: Command): void;
3
- export { registerDeployCommand };
4
- //# sourceMappingURL=deploy.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/cli/deploy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAA;AAa3C,iBAAS,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiBrD;AAwBD,OAAO,EAAE,qBAAqB,EAAE,CAAA"}
@@ -1,39 +0,0 @@
1
- import { Option } from "commander";
2
- import { randomUUID } from "node:crypto";
3
- import { z } from "zod";
4
- import { createControlPlaneClient } from "./control-plane.js";
5
- function registerDeployCommand(program) {
6
- program
7
- .command("deploy [entrypoint]")
8
- .description("Deploy actor source from a published customer image")
9
- .requiredOption("--image <reference>", "published customer build image reference")
10
- .option("--working-directory <path>", "project directory inside the build image", "/customer")
11
- .option("--revision <revision>", "code revision (defaults to a new generated ID)")
12
- .option("--url <origin>", "control-plane origin (or DURABLE_ACTORS_CONTROL_PLANE_URL)")
13
- .addOption(new Option("--project-id <id>", "actor project ID").env("DURABLE_ACTORS_PROJECT_ID"))
14
- .option("--api-key <key>", "shared secret (or DURABLE_ACTORS_SECRET)")
15
- .option("--secret <name>", "Modal secret reference (uses an on-demand sandbox)", (value, previous) => [...previous, value], [])
16
- .action(deploy);
17
- }
18
- async function deploy(entrypoint = "src/durable-objects.ts", options) {
19
- const client = createControlPlaneClient(options, fetch);
20
- const specification = deploymentSchema.parse({
21
- codeRevision: options.revision ?? randomUUID(),
22
- imageRef: options.image,
23
- workingDirectory: options.workingDirectory,
24
- actorEntrypoint: entrypoint,
25
- secretRefs: options.secret
26
- });
27
- const reply = z.object({ changed: z.boolean() }).parse(await client.registerDeployment(specification));
28
- console.log(`${reply.changed ? "Registered" : "Already registered"} revision ${specification.codeRevision}.`);
29
- }
30
- const component = z.string().regex(/^[A-Za-z0-9._-]+$/u);
31
- const deploymentSchema = z.object({
32
- codeRevision: component.max(128),
33
- imageRef: z.string().startsWith("im-").min(4).max(255),
34
- workingDirectory: z.string().startsWith("/").max(1024),
35
- actorEntrypoint: z.string().min(1).max(1024),
36
- secretRefs: z.array(component.max(255)).max(16)
37
- });
38
- export { registerDeployCommand };
39
- //# sourceMappingURL=deploy.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../src/cli/deploy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,MAAM,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAA4B,wBAAwB,EAAE,MAAM,oBAAoB,CAAA;AASvF,SAAS,qBAAqB,CAAC,OAAgB;IAC3C,OAAO;SACF,OAAO,CAAC,qBAAqB,CAAC;SAC9B,WAAW,CAAC,qDAAqD,CAAC;SAClE,cAAc,CAAC,qBAAqB,EAAE,0CAA0C,CAAC;SACjF,MAAM,CAAC,4BAA4B,EAAE,0CAA0C,EAAE,WAAW,CAAC;SAC7F,MAAM,CAAC,uBAAuB,EAAE,gDAAgD,CAAC;SACjF,MAAM,CAAC,gBAAgB,EAAE,4DAA4D,CAAC;SACtF,SAAS,CAAC,IAAI,MAAM,CAAC,mBAAmB,EAAE,kBAAkB,CAAC,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;SAC/F,MAAM,CAAC,iBAAiB,EAAE,0CAA0C,CAAC;SACrE,MAAM,CACH,iBAAiB,EACjB,oDAAoD,EACpD,CAAC,KAAa,EAAE,QAAkB,EAAE,EAAE,CAAC,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,EAC3D,EAAE,CACL;SACA,MAAM,CAAC,MAAM,CAAC,CAAA;AACvB,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,UAAU,GAAG,wBAAwB,EAAE,OAAsB;IAC/E,MAAM,MAAM,GAAG,wBAAwB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IACvD,MAAM,aAAa,GAAG,gBAAgB,CAAC,KAAK,CAAC;QACzC,YAAY,EAAE,OAAO,CAAC,QAAQ,IAAI,UAAU,EAAE;QAC9C,QAAQ,EAAE,OAAO,CAAC,KAAK;QACvB,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;QAC1C,eAAe,EAAE,UAAU;QAC3B,UAAU,EAAE,OAAO,CAAC,MAAM;KAC7B,CAAC,CAAA;IACF,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,MAAM,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC,CAAA;IACtG,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,oBAAoB,aAAa,aAAa,CAAC,YAAY,GAAG,CAAC,CAAA;AACjH,CAAC;AAED,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAA;AACxD,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,YAAY,EAAE,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;IAChC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IACtD,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;IACtD,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;IAC5C,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;CAClD,CAAC,CAAA;AAEF,OAAO,EAAE,qBAAqB,EAAE,CAAA"}
@@ -1,4 +0,0 @@
1
- import { Command } from "commander";
2
- declare function registerObjectCommands(program: Command): void;
3
- export { registerObjectCommands };
4
- //# sourceMappingURL=objects.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"objects.d.ts","sourceRoot":"","sources":["../../src/cli/objects.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAgC,MAAM,WAAW,CAAA;AA4BjE,iBAAS,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgBtD;AAwDD,OAAO,EAAE,sBAAsB,EAAE,CAAA"}