workerstack 0.1.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (605) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENSE +21 -0
  3. package/README.md +138 -0
  4. package/dist/access.d.ts +131 -0
  5. package/dist/access.d.ts.map +1 -0
  6. package/dist/access.js +333 -0
  7. package/dist/access.js.map +1 -0
  8. package/dist/api/builder.d.ts +457 -0
  9. package/dist/api/builder.d.ts.map +1 -0
  10. package/dist/api/builder.js +45 -0
  11. package/dist/api/builder.js.map +1 -0
  12. package/dist/api/catalog.d.ts +8 -0
  13. package/dist/api/catalog.d.ts.map +1 -0
  14. package/dist/api/catalog.js +56 -0
  15. package/dist/api/catalog.js.map +1 -0
  16. package/dist/api/context.d.ts +47 -0
  17. package/dist/api/context.d.ts.map +1 -0
  18. package/dist/api/context.js +40 -0
  19. package/dist/api/context.js.map +1 -0
  20. package/dist/api/crud-router.d.ts +476 -0
  21. package/dist/api/crud-router.d.ts.map +1 -0
  22. package/dist/api/crud-router.js +354 -0
  23. package/dist/api/crud-router.js.map +1 -0
  24. package/dist/api/list-input-schema.d.ts +37 -0
  25. package/dist/api/list-input-schema.d.ts.map +1 -0
  26. package/dist/api/list-input-schema.js +63 -0
  27. package/dist/api/list-input-schema.js.map +1 -0
  28. package/dist/api/list-spec.d.ts +44 -0
  29. package/dist/api/list-spec.d.ts.map +1 -0
  30. package/dist/api/list-spec.js +49 -0
  31. package/dist/api/list-spec.js.map +1 -0
  32. package/dist/api/live-view.d.ts +14 -0
  33. package/dist/api/live-view.d.ts.map +1 -0
  34. package/dist/api/live-view.js +42 -0
  35. package/dist/api/live-view.js.map +1 -0
  36. package/dist/api/live-window.d.ts +40 -0
  37. package/dist/api/live-window.d.ts.map +1 -0
  38. package/dist/api/live-window.js +93 -0
  39. package/dist/api/live-window.js.map +1 -0
  40. package/dist/api/openapi.d.ts +6 -0
  41. package/dist/api/openapi.d.ts.map +1 -0
  42. package/dist/api/openapi.js +146 -0
  43. package/dist/api/openapi.js.map +1 -0
  44. package/dist/api/realtime-router.d.ts +94 -0
  45. package/dist/api/realtime-router.d.ts.map +1 -0
  46. package/dist/api/realtime-router.js +45 -0
  47. package/dist/api/realtime-router.js.map +1 -0
  48. package/dist/api/registry.d.ts +30 -0
  49. package/dist/api/registry.d.ts.map +1 -0
  50. package/dist/api/registry.js +236 -0
  51. package/dist/api/registry.js.map +1 -0
  52. package/dist/api/router.d.ts +15 -0
  53. package/dist/api/router.d.ts.map +1 -0
  54. package/dist/api/router.js +32 -0
  55. package/dist/api/router.js.map +1 -0
  56. package/dist/api/storage-router.d.ts +349 -0
  57. package/dist/api/storage-router.d.ts.map +1 -0
  58. package/dist/api/storage-router.js +155 -0
  59. package/dist/api/storage-router.js.map +1 -0
  60. package/dist/api/types.d.ts +55 -0
  61. package/dist/api/types.d.ts.map +1 -0
  62. package/dist/api/types.js +2 -0
  63. package/dist/api/types.js.map +1 -0
  64. package/dist/auth-password.d.ts +27 -0
  65. package/dist/auth-password.d.ts.map +1 -0
  66. package/dist/auth-password.js +60 -0
  67. package/dist/auth-password.js.map +1 -0
  68. package/dist/auth.d.ts +59 -0
  69. package/dist/auth.d.ts.map +1 -0
  70. package/dist/auth.js +146 -0
  71. package/dist/auth.js.map +1 -0
  72. package/dist/backend-internals.d.ts +35 -0
  73. package/dist/backend-internals.d.ts.map +1 -0
  74. package/dist/backend-internals.js +2 -0
  75. package/dist/backend-internals.js.map +1 -0
  76. package/dist/backend.d.ts +63 -0
  77. package/dist/backend.d.ts.map +1 -0
  78. package/dist/backend.js +59 -0
  79. package/dist/backend.js.map +1 -0
  80. package/dist/blueprint-generator.d.ts +21 -0
  81. package/dist/blueprint-generator.d.ts.map +1 -0
  82. package/dist/blueprint-generator.js +199 -0
  83. package/dist/blueprint-generator.js.map +1 -0
  84. package/dist/blueprint.d.ts +99 -0
  85. package/dist/blueprint.d.ts.map +1 -0
  86. package/dist/blueprint.js +257 -0
  87. package/dist/blueprint.js.map +1 -0
  88. package/dist/cli-skills.d.ts +16 -0
  89. package/dist/cli-skills.d.ts.map +1 -0
  90. package/dist/cli-skills.js +108 -0
  91. package/dist/cli-skills.js.map +1 -0
  92. package/dist/cli.d.ts +18 -0
  93. package/dist/cli.d.ts.map +1 -0
  94. package/dist/cli.js +205 -0
  95. package/dist/cli.js.map +1 -0
  96. package/dist/client/client.d.ts +53 -0
  97. package/dist/client/client.d.ts.map +1 -0
  98. package/dist/client/client.js +111 -0
  99. package/dist/client/client.js.map +1 -0
  100. package/dist/client/index.d.ts +4 -0
  101. package/dist/client/index.d.ts.map +1 -0
  102. package/dist/client/index.js +4 -0
  103. package/dist/client/index.js.map +1 -0
  104. package/dist/client/live-view.d.ts +49 -0
  105. package/dist/client/live-view.d.ts.map +1 -0
  106. package/dist/client/live-view.js +184 -0
  107. package/dist/client/live-view.js.map +1 -0
  108. package/dist/client/react.d.ts +4 -0
  109. package/dist/client/react.d.ts.map +1 -0
  110. package/dist/client/react.js +6 -0
  111. package/dist/client/react.js.map +1 -0
  112. package/dist/client/realtime.d.ts +54 -0
  113. package/dist/client/realtime.d.ts.map +1 -0
  114. package/dist/client/realtime.js +105 -0
  115. package/dist/client/realtime.js.map +1 -0
  116. package/dist/client/rest.d.ts +2 -0
  117. package/dist/client/rest.d.ts.map +1 -0
  118. package/dist/client/rest.js +2 -0
  119. package/dist/client/rest.js.map +1 -0
  120. package/dist/client/rpc-client.d.ts +38 -0
  121. package/dist/client/rpc-client.d.ts.map +1 -0
  122. package/dist/client/rpc-client.js +59 -0
  123. package/dist/client/rpc-client.js.map +1 -0
  124. package/dist/client/solid.d.ts +7 -0
  125. package/dist/client/solid.d.ts.map +1 -0
  126. package/dist/client/solid.js +21 -0
  127. package/dist/client/solid.js.map +1 -0
  128. package/dist/client/svelte.d.ts +6 -0
  129. package/dist/client/svelte.d.ts.map +1 -0
  130. package/dist/client/svelte.js +9 -0
  131. package/dist/client/svelte.js.map +1 -0
  132. package/dist/client/vue.d.ts +5 -0
  133. package/dist/client/vue.d.ts.map +1 -0
  134. package/dist/client/vue.js +11 -0
  135. package/dist/client/vue.js.map +1 -0
  136. package/dist/codegen.d.ts +36 -0
  137. package/dist/codegen.d.ts.map +1 -0
  138. package/dist/codegen.js +235 -0
  139. package/dist/codegen.js.map +1 -0
  140. package/dist/config.d.ts +129 -0
  141. package/dist/config.d.ts.map +1 -0
  142. package/dist/config.js +75 -0
  143. package/dist/config.js.map +1 -0
  144. package/dist/cron.d.ts +4 -0
  145. package/dist/cron.d.ts.map +1 -0
  146. package/dist/cron.js +3 -0
  147. package/dist/cron.js.map +1 -0
  148. package/dist/crud-operations.d.ts +43 -0
  149. package/dist/crud-operations.d.ts.map +1 -0
  150. package/dist/crud-operations.js +249 -0
  151. package/dist/crud-operations.js.map +1 -0
  152. package/dist/database/adapter.d.ts +26 -0
  153. package/dist/database/adapter.d.ts.map +1 -0
  154. package/dist/database/adapter.js +2 -0
  155. package/dist/database/adapter.js.map +1 -0
  156. package/dist/database/libsql.d.ts +3 -0
  157. package/dist/database/libsql.d.ts.map +1 -0
  158. package/dist/database/libsql.js +39 -0
  159. package/dist/database/libsql.js.map +1 -0
  160. package/dist/db.d.ts +15 -0
  161. package/dist/db.d.ts.map +1 -0
  162. package/dist/db.js +8 -0
  163. package/dist/db.js.map +1 -0
  164. package/dist/dev/binaries.d.ts +22 -0
  165. package/dist/dev/binaries.d.ts.map +1 -0
  166. package/dist/dev/binaries.js +119 -0
  167. package/dist/dev/binaries.js.map +1 -0
  168. package/dist/dev/env.d.ts +11 -0
  169. package/dist/dev/env.d.ts.map +1 -0
  170. package/dist/dev/env.js +71 -0
  171. package/dist/dev/env.js.map +1 -0
  172. package/dist/dev/index.d.ts +39 -0
  173. package/dist/dev/index.d.ts.map +1 -0
  174. package/dist/dev/index.js +273 -0
  175. package/dist/dev/index.js.map +1 -0
  176. package/dist/dev/processes.d.ts +37 -0
  177. package/dist/dev/processes.d.ts.map +1 -0
  178. package/dist/dev/processes.js +104 -0
  179. package/dist/dev/processes.js.map +1 -0
  180. package/dist/dev/push.d.ts +2 -0
  181. package/dist/dev/push.d.ts.map +1 -0
  182. package/dist/dev/push.js +30 -0
  183. package/dist/dev/push.js.map +1 -0
  184. package/dist/dialect.d.ts +17 -0
  185. package/dist/dialect.d.ts.map +1 -0
  186. package/dist/dialect.js +12 -0
  187. package/dist/dialect.js.map +1 -0
  188. package/dist/email/smtp.d.ts +20 -0
  189. package/dist/email/smtp.d.ts.map +1 -0
  190. package/dist/email/smtp.js +31 -0
  191. package/dist/email/smtp.js.map +1 -0
  192. package/dist/email.d.ts +26 -0
  193. package/dist/email.d.ts.map +1 -0
  194. package/dist/email.js +2 -0
  195. package/dist/email.js.map +1 -0
  196. package/dist/env-probe.d.ts +9 -0
  197. package/dist/env-probe.d.ts.map +1 -0
  198. package/dist/env-probe.js +72 -0
  199. package/dist/env-probe.js.map +1 -0
  200. package/dist/env.d.ts +62 -0
  201. package/dist/env.d.ts.map +1 -0
  202. package/dist/env.js +86 -0
  203. package/dist/env.js.map +1 -0
  204. package/dist/errors.d.ts +153 -0
  205. package/dist/errors.d.ts.map +1 -0
  206. package/dist/errors.js +106 -0
  207. package/dist/errors.js.map +1 -0
  208. package/dist/handler.d.ts +11 -0
  209. package/dist/handler.d.ts.map +1 -0
  210. package/dist/handler.js +21 -0
  211. package/dist/handler.js.map +1 -0
  212. package/dist/hosted-contract.d.ts +11 -0
  213. package/dist/hosted-contract.d.ts.map +1 -0
  214. package/dist/hosted-contract.js +50 -0
  215. package/dist/hosted-contract.js.map +1 -0
  216. package/dist/idempotency.d.ts +17 -0
  217. package/dist/idempotency.d.ts.map +1 -0
  218. package/dist/idempotency.js +65 -0
  219. package/dist/idempotency.js.map +1 -0
  220. package/dist/index.d.ts +41 -0
  221. package/dist/index.d.ts.map +1 -0
  222. package/dist/index.js +18 -0
  223. package/dist/index.js.map +1 -0
  224. package/dist/inspect.d.ts +15 -0
  225. package/dist/inspect.d.ts.map +1 -0
  226. package/dist/inspect.js +44 -0
  227. package/dist/inspect.js.map +1 -0
  228. package/dist/internal-tables.d.ts +1767 -0
  229. package/dist/internal-tables.d.ts.map +1 -0
  230. package/dist/internal-tables.js +114 -0
  231. package/dist/internal-tables.js.map +1 -0
  232. package/dist/jobs/cron.d.ts +15 -0
  233. package/dist/jobs/cron.d.ts.map +1 -0
  234. package/dist/jobs/cron.js +74 -0
  235. package/dist/jobs/cron.js.map +1 -0
  236. package/dist/jobs/define.d.ts +186 -0
  237. package/dist/jobs/define.d.ts.map +1 -0
  238. package/dist/jobs/define.js +99 -0
  239. package/dist/jobs/define.js.map +1 -0
  240. package/dist/jobs/index.d.ts +9 -0
  241. package/dist/jobs/index.d.ts.map +1 -0
  242. package/dist/jobs/index.js +7 -0
  243. package/dist/jobs/index.js.map +1 -0
  244. package/dist/jobs/queue.d.ts +13 -0
  245. package/dist/jobs/queue.d.ts.map +1 -0
  246. package/dist/jobs/queue.js +71 -0
  247. package/dist/jobs/queue.js.map +1 -0
  248. package/dist/jobs/slots.d.ts +30 -0
  249. package/dist/jobs/slots.d.ts.map +1 -0
  250. package/dist/jobs/slots.js +53 -0
  251. package/dist/jobs/slots.js.map +1 -0
  252. package/dist/jobs/worker.d.ts +45 -0
  253. package/dist/jobs/worker.d.ts.map +1 -0
  254. package/dist/jobs/worker.js +605 -0
  255. package/dist/jobs/worker.js.map +1 -0
  256. package/dist/lifecycle.d.ts +10 -0
  257. package/dist/lifecycle.d.ts.map +1 -0
  258. package/dist/lifecycle.js +37 -0
  259. package/dist/lifecycle.js.map +1 -0
  260. package/dist/list-query.d.ts +62 -0
  261. package/dist/list-query.d.ts.map +1 -0
  262. package/dist/list-query.js +190 -0
  263. package/dist/list-query.js.map +1 -0
  264. package/dist/live/apply.d.ts +13 -0
  265. package/dist/live/apply.d.ts.map +1 -0
  266. package/dist/live/apply.js +32 -0
  267. package/dist/live/apply.js.map +1 -0
  268. package/dist/live/index.d.ts +48 -0
  269. package/dist/live/index.d.ts.map +1 -0
  270. package/dist/live/index.js +108 -0
  271. package/dist/live/index.js.map +1 -0
  272. package/dist/live/protocol.d.ts +47 -0
  273. package/dist/live/protocol.d.ts.map +1 -0
  274. package/dist/live/protocol.js +12 -0
  275. package/dist/live/protocol.js.map +1 -0
  276. package/dist/live/sse.d.ts +22 -0
  277. package/dist/live/sse.d.ts.map +1 -0
  278. package/dist/live/sse.js +41 -0
  279. package/dist/live/sse.js.map +1 -0
  280. package/dist/logging.d.ts +8 -0
  281. package/dist/logging.d.ts.map +1 -0
  282. package/dist/logging.js +6 -0
  283. package/dist/logging.js.map +1 -0
  284. package/dist/manifest-diff.d.ts +6 -0
  285. package/dist/manifest-diff.d.ts.map +1 -0
  286. package/dist/manifest-diff.js +42 -0
  287. package/dist/manifest-diff.js.map +1 -0
  288. package/dist/manifest.d.ts +87 -0
  289. package/dist/manifest.d.ts.map +1 -0
  290. package/dist/manifest.js +237 -0
  291. package/dist/manifest.js.map +1 -0
  292. package/dist/messaging/email.d.ts +16 -0
  293. package/dist/messaging/email.d.ts.map +1 -0
  294. package/dist/messaging/email.js +8 -0
  295. package/dist/messaging/email.js.map +1 -0
  296. package/dist/messaging/index.d.ts +8 -0
  297. package/dist/messaging/index.d.ts.map +1 -0
  298. package/dist/messaging/index.js +4 -0
  299. package/dist/messaging/index.js.map +1 -0
  300. package/dist/messaging/journal.d.ts +4 -0
  301. package/dist/messaging/journal.d.ts.map +1 -0
  302. package/dist/messaging/journal.js +19 -0
  303. package/dist/messaging/journal.js.map +1 -0
  304. package/dist/messaging/runtime.d.ts +16 -0
  305. package/dist/messaging/runtime.d.ts.map +1 -0
  306. package/dist/messaging/runtime.js +213 -0
  307. package/dist/messaging/runtime.js.map +1 -0
  308. package/dist/messaging/standalone.d.ts +27 -0
  309. package/dist/messaging/standalone.d.ts.map +1 -0
  310. package/dist/messaging/standalone.js +18 -0
  311. package/dist/messaging/standalone.js.map +1 -0
  312. package/dist/messaging/telegram.d.ts +16 -0
  313. package/dist/messaging/telegram.d.ts.map +1 -0
  314. package/dist/messaging/telegram.js +5 -0
  315. package/dist/messaging/telegram.js.map +1 -0
  316. package/dist/messaging/types.d.ts +22 -0
  317. package/dist/messaging/types.d.ts.map +1 -0
  318. package/dist/messaging/types.js +17 -0
  319. package/dist/messaging/types.js.map +1 -0
  320. package/dist/platform.d.ts +25 -0
  321. package/dist/platform.d.ts.map +1 -0
  322. package/dist/platform.js +24 -0
  323. package/dist/platform.js.map +1 -0
  324. package/dist/provision-internals.d.ts +23 -0
  325. package/dist/provision-internals.d.ts.map +1 -0
  326. package/dist/provision-internals.js +7 -0
  327. package/dist/provision-internals.js.map +1 -0
  328. package/dist/provision-runtime.d.ts +6 -0
  329. package/dist/provision-runtime.d.ts.map +1 -0
  330. package/dist/provision-runtime.js +41 -0
  331. package/dist/provision-runtime.js.map +1 -0
  332. package/dist/provision-schema.d.ts +16 -0
  333. package/dist/provision-schema.d.ts.map +1 -0
  334. package/dist/provision-schema.js +59 -0
  335. package/dist/provision-schema.js.map +1 -0
  336. package/dist/provision.d.ts +8 -0
  337. package/dist/provision.d.ts.map +1 -0
  338. package/dist/provision.js +16 -0
  339. package/dist/provision.js.map +1 -0
  340. package/dist/query/api.d.ts +10 -0
  341. package/dist/query/api.d.ts.map +1 -0
  342. package/dist/query/api.js +7 -0
  343. package/dist/query/api.js.map +1 -0
  344. package/dist/query/client.d.ts +28 -0
  345. package/dist/query/client.d.ts.map +1 -0
  346. package/dist/query/client.js +87 -0
  347. package/dist/query/client.js.map +1 -0
  348. package/dist/query/fetch.d.ts +3 -0
  349. package/dist/query/fetch.d.ts.map +1 -0
  350. package/dist/query/fetch.js +4 -0
  351. package/dist/query/fetch.js.map +1 -0
  352. package/dist/query/index.d.ts +8 -0
  353. package/dist/query/index.d.ts.map +1 -0
  354. package/dist/query/index.js +4 -0
  355. package/dist/query/index.js.map +1 -0
  356. package/dist/query/infer.d.ts +25 -0
  357. package/dist/query/infer.d.ts.map +1 -0
  358. package/dist/query/infer.js +2 -0
  359. package/dist/query/infer.js.map +1 -0
  360. package/dist/query/react.d.ts +3 -0
  361. package/dist/query/react.d.ts.map +1 -0
  362. package/dist/query/react.js +2 -0
  363. package/dist/query/react.js.map +1 -0
  364. package/dist/query/realtime-flush.d.ts +26 -0
  365. package/dist/query/realtime-flush.d.ts.map +1 -0
  366. package/dist/query/realtime-flush.js +45 -0
  367. package/dist/query/realtime-flush.js.map +1 -0
  368. package/dist/query/realtime-stream.d.ts +3 -0
  369. package/dist/query/realtime-stream.d.ts.map +1 -0
  370. package/dist/query/realtime-stream.js +3 -0
  371. package/dist/query/realtime-stream.js.map +1 -0
  372. package/dist/query/realtime.d.ts +88 -0
  373. package/dist/query/realtime.d.ts.map +1 -0
  374. package/dist/query/realtime.js +255 -0
  375. package/dist/query/realtime.js.map +1 -0
  376. package/dist/rate-limit.d.ts +8 -0
  377. package/dist/rate-limit.d.ts.map +1 -0
  378. package/dist/rate-limit.js +46 -0
  379. package/dist/rate-limit.js.map +1 -0
  380. package/dist/readiness-probes.d.ts +4 -0
  381. package/dist/readiness-probes.d.ts.map +1 -0
  382. package/dist/readiness-probes.js +23 -0
  383. package/dist/readiness-probes.js.map +1 -0
  384. package/dist/readiness.d.ts +39 -0
  385. package/dist/readiness.d.ts.map +1 -0
  386. package/dist/readiness.js +72 -0
  387. package/dist/readiness.js.map +1 -0
  388. package/dist/realtime/facade.d.ts +20 -0
  389. package/dist/realtime/facade.d.ts.map +1 -0
  390. package/dist/realtime/facade.js +37 -0
  391. package/dist/realtime/facade.js.map +1 -0
  392. package/dist/realtime/filter.d.ts +42 -0
  393. package/dist/realtime/filter.d.ts.map +1 -0
  394. package/dist/realtime/filter.js +86 -0
  395. package/dist/realtime/filter.js.map +1 -0
  396. package/dist/realtime/heartbeat.d.ts +20 -0
  397. package/dist/realtime/heartbeat.d.ts.map +1 -0
  398. package/dist/realtime/heartbeat.js +64 -0
  399. package/dist/realtime/heartbeat.js.map +1 -0
  400. package/dist/realtime/publisher.d.ts +19 -0
  401. package/dist/realtime/publisher.d.ts.map +1 -0
  402. package/dist/realtime/publisher.js +8 -0
  403. package/dist/realtime/publisher.js.map +1 -0
  404. package/dist/runtime.d.ts +141 -0
  405. package/dist/runtime.d.ts.map +1 -0
  406. package/dist/runtime.js +463 -0
  407. package/dist/runtime.js.map +1 -0
  408. package/dist/schema-export.d.ts +2 -0
  409. package/dist/schema-export.d.ts.map +1 -0
  410. package/dist/schema-export.js +2 -0
  411. package/dist/schema-export.js.map +1 -0
  412. package/dist/scope.d.ts +4 -0
  413. package/dist/scope.d.ts.map +1 -0
  414. package/dist/scope.js +13 -0
  415. package/dist/scope.js.map +1 -0
  416. package/dist/standard-schema.d.ts +13 -0
  417. package/dist/standard-schema.d.ts.map +1 -0
  418. package/dist/standard-schema.js +34 -0
  419. package/dist/standard-schema.js.map +1 -0
  420. package/dist/start/auth-client.d.ts +11 -0
  421. package/dist/start/auth-client.d.ts.map +1 -0
  422. package/dist/start/auth-client.js +15 -0
  423. package/dist/start/auth-client.js.map +1 -0
  424. package/dist/start/create-start-worker.d.ts +16 -0
  425. package/dist/start/create-start-worker.d.ts.map +1 -0
  426. package/dist/start/create-start-worker.js +24 -0
  427. package/dist/start/create-start-worker.js.map +1 -0
  428. package/dist/start/index.d.ts +66 -0
  429. package/dist/start/index.d.ts.map +1 -0
  430. package/dist/start/index.js +49 -0
  431. package/dist/start/index.js.map +1 -0
  432. package/dist/start/isomorphic-fetch.d.ts +22 -0
  433. package/dist/start/isomorphic-fetch.d.ts.map +1 -0
  434. package/dist/start/isomorphic-fetch.js +49 -0
  435. package/dist/start/isomorphic-fetch.js.map +1 -0
  436. package/dist/start/server-entry.d.ts +7 -0
  437. package/dist/start/server-entry.d.ts.map +1 -0
  438. package/dist/start/server-entry.js +8 -0
  439. package/dist/start/server-entry.js.map +1 -0
  440. package/dist/storage/background.d.ts +3 -0
  441. package/dist/storage/background.d.ts.map +1 -0
  442. package/dist/storage/background.js +3 -0
  443. package/dist/storage/background.js.map +1 -0
  444. package/dist/storage/buckets.d.ts +78 -0
  445. package/dist/storage/buckets.d.ts.map +1 -0
  446. package/dist/storage/buckets.js +177 -0
  447. package/dist/storage/buckets.js.map +1 -0
  448. package/dist/storage/delete.d.ts +8 -0
  449. package/dist/storage/delete.d.ts.map +1 -0
  450. package/dist/storage/delete.js +10 -0
  451. package/dist/storage/delete.js.map +1 -0
  452. package/dist/storage/file-meta.d.ts +37 -0
  453. package/dist/storage/file-meta.d.ts.map +1 -0
  454. package/dist/storage/file-meta.js +166 -0
  455. package/dist/storage/file-meta.js.map +1 -0
  456. package/dist/storage/index.d.ts +28 -0
  457. package/dist/storage/index.d.ts.map +1 -0
  458. package/dist/storage/index.js +5 -0
  459. package/dist/storage/index.js.map +1 -0
  460. package/dist/storage/local.d.ts +15 -0
  461. package/dist/storage/local.d.ts.map +1 -0
  462. package/dist/storage/local.js +56 -0
  463. package/dist/storage/local.js.map +1 -0
  464. package/dist/storage/operations.d.ts +54 -0
  465. package/dist/storage/operations.d.ts.map +1 -0
  466. package/dist/storage/operations.js +212 -0
  467. package/dist/storage/operations.js.map +1 -0
  468. package/dist/storage/registry.d.ts +11 -0
  469. package/dist/storage/registry.d.ts.map +1 -0
  470. package/dist/storage/registry.js +23 -0
  471. package/dist/storage/registry.js.map +1 -0
  472. package/dist/storage/s3.d.ts +35 -0
  473. package/dist/storage/s3.d.ts.map +1 -0
  474. package/dist/storage/s3.js +125 -0
  475. package/dist/storage/s3.js.map +1 -0
  476. package/dist/storage/sigv4.d.ts +24 -0
  477. package/dist/storage/sigv4.d.ts.map +1 -0
  478. package/dist/storage/sigv4.js +107 -0
  479. package/dist/storage/sigv4.js.map +1 -0
  480. package/dist/storage/sweep.d.ts +9 -0
  481. package/dist/storage/sweep.d.ts.map +1 -0
  482. package/dist/storage/sweep.js +17 -0
  483. package/dist/storage/sweep.js.map +1 -0
  484. package/dist/sync/collection.d.ts +106 -0
  485. package/dist/sync/collection.d.ts.map +1 -0
  486. package/dist/sync/collection.js +258 -0
  487. package/dist/sync/collection.js.map +1 -0
  488. package/dist/sync/index.d.ts +8 -0
  489. package/dist/sync/index.d.ts.map +1 -0
  490. package/dist/sync/index.js +4 -0
  491. package/dist/sync/index.js.map +1 -0
  492. package/dist/sync/realtime-sync.d.ts +31 -0
  493. package/dist/sync/realtime-sync.d.ts.map +1 -0
  494. package/dist/sync/realtime-sync.js +46 -0
  495. package/dist/sync/realtime-sync.js.map +1 -0
  496. package/dist/sync/sync-client.d.ts +28 -0
  497. package/dist/sync/sync-client.d.ts.map +1 -0
  498. package/dist/sync/sync-client.js +52 -0
  499. package/dist/sync/sync-client.js.map +1 -0
  500. package/dist/sync/update-queue.d.ts +27 -0
  501. package/dist/sync/update-queue.d.ts.map +1 -0
  502. package/dist/sync/update-queue.js +66 -0
  503. package/dist/sync/update-queue.js.map +1 -0
  504. package/dist/testing/auth.d.ts +85 -0
  505. package/dist/testing/auth.d.ts.map +1 -0
  506. package/dist/testing/auth.js +140 -0
  507. package/dist/testing/auth.js.map +1 -0
  508. package/dist/testing/client.d.ts +6 -0
  509. package/dist/testing/client.d.ts.map +1 -0
  510. package/dist/testing/client.js +9 -0
  511. package/dist/testing/client.js.map +1 -0
  512. package/dist/testing/database.d.ts +6 -0
  513. package/dist/testing/database.d.ts.map +1 -0
  514. package/dist/testing/database.js +8 -0
  515. package/dist/testing/database.js.map +1 -0
  516. package/dist/testing/email.d.ts +15 -0
  517. package/dist/testing/email.d.ts.map +1 -0
  518. package/dist/testing/email.js +32 -0
  519. package/dist/testing/email.js.map +1 -0
  520. package/dist/testing/fixture.d.ts +51 -0
  521. package/dist/testing/fixture.d.ts.map +1 -0
  522. package/dist/testing/fixture.js +177 -0
  523. package/dist/testing/fixture.js.map +1 -0
  524. package/dist/testing/jobs.d.ts +40 -0
  525. package/dist/testing/jobs.d.ts.map +1 -0
  526. package/dist/testing/jobs.js +76 -0
  527. package/dist/testing/jobs.js.map +1 -0
  528. package/dist/testing/logs.d.ts +18 -0
  529. package/dist/testing/logs.d.ts.map +1 -0
  530. package/dist/testing/logs.js +53 -0
  531. package/dist/testing/logs.js.map +1 -0
  532. package/dist/testing/messaging.d.ts +21 -0
  533. package/dist/testing/messaging.d.ts.map +1 -0
  534. package/dist/testing/messaging.js +34 -0
  535. package/dist/testing/messaging.js.map +1 -0
  536. package/dist/testing/storage.d.ts +7 -0
  537. package/dist/testing/storage.d.ts.map +1 -0
  538. package/dist/testing/storage.js +29 -0
  539. package/dist/testing/storage.js.map +1 -0
  540. package/dist/testing/workers-fakes.d.ts +17 -0
  541. package/dist/testing/workers-fakes.d.ts.map +1 -0
  542. package/dist/testing/workers-fakes.js +98 -0
  543. package/dist/testing/workers-fakes.js.map +1 -0
  544. package/dist/testing.d.ts +12 -0
  545. package/dist/testing.d.ts.map +1 -0
  546. package/dist/testing.js +5 -0
  547. package/dist/testing.js.map +1 -0
  548. package/dist/typeid.d.ts +46 -0
  549. package/dist/typeid.d.ts.map +1 -0
  550. package/dist/typeid.js +130 -0
  551. package/dist/typeid.js.map +1 -0
  552. package/dist/vite.d.ts +26 -0
  553. package/dist/vite.d.ts.map +1 -0
  554. package/dist/vite.js +100 -0
  555. package/dist/vite.js.map +1 -0
  556. package/dist/worker-plan.d.ts +37 -0
  557. package/dist/worker-plan.d.ts.map +1 -0
  558. package/dist/worker-plan.js +63 -0
  559. package/dist/worker-plan.js.map +1 -0
  560. package/dist/workers/app.d.ts +19 -0
  561. package/dist/workers/app.d.ts.map +1 -0
  562. package/dist/workers/app.js +56 -0
  563. package/dist/workers/app.js.map +1 -0
  564. package/dist/workers/entry.d.ts +7 -0
  565. package/dist/workers/entry.d.ts.map +1 -0
  566. package/dist/workers/entry.js +8 -0
  567. package/dist/workers/entry.js.map +1 -0
  568. package/dist/workers/index.d.ts +23 -0
  569. package/dist/workers/index.d.ts.map +1 -0
  570. package/dist/workers/index.js +39 -0
  571. package/dist/workers/index.js.map +1 -0
  572. package/dist/workers/r2.d.ts +24 -0
  573. package/dist/workers/r2.d.ts.map +1 -0
  574. package/dist/workers/r2.js +76 -0
  575. package/dist/workers/r2.js.map +1 -0
  576. package/dist/workers/rate-limiter.d.ts +9 -0
  577. package/dist/workers/rate-limiter.d.ts.map +1 -0
  578. package/dist/workers/rate-limiter.js +22 -0
  579. package/dist/workers/rate-limiter.js.map +1 -0
  580. package/dist/workers/realtime-hub.d.ts +20 -0
  581. package/dist/workers/realtime-hub.d.ts.map +1 -0
  582. package/dist/workers/realtime-hub.js +117 -0
  583. package/dist/workers/realtime-hub.js.map +1 -0
  584. package/dist/workers/registry.d.ts +13 -0
  585. package/dist/workers/registry.d.ts.map +1 -0
  586. package/dist/workers/registry.js +19 -0
  587. package/dist/workers/registry.js.map +1 -0
  588. package/dist/workers/scheduler.d.ts +13 -0
  589. package/dist/workers/scheduler.d.ts.map +1 -0
  590. package/dist/workers/scheduler.js +71 -0
  591. package/dist/workers/scheduler.js.map +1 -0
  592. package/dist/workers/types.d.ts +55 -0
  593. package/dist/workers/types.d.ts.map +1 -0
  594. package/dist/workers/types.js +4 -0
  595. package/dist/workers/types.js.map +1 -0
  596. package/dist/workers/wrangler.d.ts +62 -0
  597. package/dist/workers/wrangler.d.ts.map +1 -0
  598. package/dist/workers/wrangler.js +90 -0
  599. package/dist/workers/wrangler.js.map +1 -0
  600. package/package.json +286 -0
  601. package/skills/creating-workerstack-apps/SKILL.md +45 -0
  602. package/skills/creating-workerstack-apps/agents/openai.yaml +4 -0
  603. package/skills/creating-workerstack-apps/references/application-structure.md +219 -0
  604. package/skills/creating-workerstack-apps/references/runtime-integrations.md +96 -0
  605. package/skills/creating-workerstack-apps/references/verification.md +29 -0
@@ -0,0 +1,22 @@
1
+ export type BinaryName = 'celld' | 'sqld';
2
+ export type Pin = {
3
+ version: string;
4
+ format: 'gz' | 'tar.xz';
5
+ url: (target: string) => string;
6
+ /** sha256 of the downloaded asset, per release target. */
7
+ sha256: Partial<Record<string, string>>;
8
+ };
9
+ export type Pins = Partial<Record<BinaryName, Pin>>;
10
+ export type ResolveOptions = {
11
+ env?: Record<string, string | undefined>;
12
+ cacheDir?: string;
13
+ platform?: string;
14
+ arch?: string;
15
+ fetch?: (url: string) => Promise<Response>;
16
+ log?: (message: string) => void;
17
+ /** Replaces the pinned table; for tests. */
18
+ pins?: Pins;
19
+ };
20
+ export declare function binaryTarget(platform: string, arch: string): string | undefined;
21
+ export declare function resolveBinary(name: BinaryName, options?: ResolveOptions): Promise<string>;
22
+ //# sourceMappingURL=binaries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binaries.d.ts","sourceRoot":"","sources":["../../src/dev/binaries.ts"],"names":[],"mappings":"AAiBA,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,CAAA;AAEzC,MAAM,MAAM,GAAG,GAAG;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,IAAI,GAAG,QAAQ,CAAA;IACvB,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAA;IAC/B,0DAA0D;IAC1D,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CACxC,CAAA;AAED,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAA;AAmCnD,MAAM,MAAM,cAAc,GAAG;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC1C,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,4CAA4C;IAC5C,IAAI,CAAC,EAAE,IAAI,CAAA;CACZ,CAAA;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,sBAM1D;AAyBD,wBAAsB,aAAa,CACjC,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,MAAM,CAAC,CAmEjB"}
@@ -0,0 +1,119 @@
1
+ // Pinned celld and sqld binaries for `workerstack dev`. The first run
2
+ // downloads them to ~/.cache/workerstack and checks their sha256; an env var
3
+ // selects a system binary instead.
4
+ import { access, chmod, constants, mkdir, mkdtemp, readdir, rename, rm, stat, } from 'node:fs/promises';
5
+ import { homedir } from 'node:os';
6
+ import { join } from 'node:path';
7
+ const PINS = {
8
+ celld: {
9
+ version: 'v0.6.0',
10
+ format: 'gz',
11
+ url: (target) => `https://github.com/denoland/celld/releases/download/v0.6.0/celld-${target}.gz`,
12
+ sha256: {
13
+ 'aarch64-apple-darwin': 'bf6f0c06c4f815eecddf61ae40340935a0dbf76be3d643bf75fdd92bfac425cd',
14
+ 'aarch64-unknown-linux-gnu': '3d4945df3abcc6832b6e7fa978b9ee3c26e46a0b7791924843d42c0ed14eff96',
15
+ 'x86_64-unknown-linux-gnu': '8f1e18072c234ab75459d4da104c13cebc9b29a3e4a4772086bf985829bea8aa',
16
+ },
17
+ },
18
+ sqld: {
19
+ version: 'v0.24.32',
20
+ format: 'tar.xz',
21
+ url: (target) => `https://github.com/tursodatabase/libsql/releases/download/libsql-server-v0.24.32/libsql-server-${target}.tar.xz`,
22
+ sha256: {
23
+ 'aarch64-apple-darwin': 'ced2a9d65a5d4b6bd72c67e98ad6c63139e2a139d91769f07fdd15be935381dd',
24
+ 'x86_64-apple-darwin': '461480ea5a17781bab7dd5974aa804007434611baced37b6349c8060d0648e34',
25
+ 'aarch64-unknown-linux-gnu': '37f9eee45b388a30192907ecf4565b93df945c079331657073b5b3caf8bb1cd0',
26
+ 'x86_64-unknown-linux-gnu': '71720fc8648c19efef416efebd47145ef59b62e198770533530a858e1336879f',
27
+ },
28
+ },
29
+ };
30
+ export function binaryTarget(platform, arch) {
31
+ const cpu = arch === 'arm64' ? 'aarch64' : arch === 'x64' ? 'x86_64' : '';
32
+ if (!cpu)
33
+ return undefined;
34
+ if (platform === 'darwin')
35
+ return `${cpu}-apple-darwin`;
36
+ if (platform === 'linux')
37
+ return `${cpu}-unknown-linux-gnu`;
38
+ return undefined;
39
+ }
40
+ async function isExecutable(path) {
41
+ return access(path, constants.X_OK).then(() => true, () => false);
42
+ }
43
+ async function findFile(dir, name) {
44
+ for (const entry of await readdir(dir, { withFileTypes: true })) {
45
+ const path = join(dir, entry.name);
46
+ if (entry.isDirectory()) {
47
+ const found = await findFile(path, name);
48
+ if (found)
49
+ return found;
50
+ }
51
+ else if (entry.name === name) {
52
+ return path;
53
+ }
54
+ }
55
+ return undefined;
56
+ }
57
+ export async function resolveBinary(name, options = {}) {
58
+ const env = options.env ?? process.env;
59
+ const envName = `WORKERSTACK_${name.toUpperCase()}_BIN`;
60
+ const override = env[envName];
61
+ if (override)
62
+ return override;
63
+ const pin = (options.pins ?? PINS)[name];
64
+ const target = binaryTarget(options.platform ?? process.platform, options.arch ?? process.arch);
65
+ const checksum = target ? pin?.sha256[target] : undefined;
66
+ if (!pin || !target || !checksum) {
67
+ throw new Error(`[workerstack] no ${name} build for ${options.platform ?? process.platform} ${options.arch ?? process.arch}; install ${name} and set ${envName} to its path`);
68
+ }
69
+ const cacheDir = options.cacheDir ??
70
+ env.WORKERSTACK_CACHE_DIR ??
71
+ join(homedir(), '.cache', 'workerstack');
72
+ const home = join(cacheDir, `${name}-${pin.version}-${target}`);
73
+ const cached = await findFile(home, name).catch(() => undefined);
74
+ if (cached && (await isExecutable(cached)))
75
+ return cached;
76
+ const url = pin.url(target);
77
+ options.log?.(`downloading ${name} ${pin.version} from ${url}`);
78
+ const response = await (options.fetch ?? fetch)(url);
79
+ if (!response.ok) {
80
+ throw new Error(`[workerstack] ${url} returned ${response.status}`);
81
+ }
82
+ const bytes = new Uint8Array(await response.arrayBuffer());
83
+ const actual = new Bun.CryptoHasher('sha256').update(bytes).digest('hex');
84
+ if (actual !== checksum) {
85
+ throw new Error(`[workerstack] ${name} checksum mismatch: expected ${checksum}, got ${actual}`);
86
+ }
87
+ await mkdir(cacheDir, { recursive: true });
88
+ const staging = await mkdtemp(join(cacheDir, `.${name}-`));
89
+ try {
90
+ if (pin.format === 'gz') {
91
+ await Bun.write(join(staging, name), Bun.gunzipSync(bytes));
92
+ }
93
+ else {
94
+ const archive = join(staging, 'asset.tar.xz');
95
+ await Bun.write(archive, bytes);
96
+ const tar = Bun.spawnSync(['tar', '-xJf', archive], { cwd: staging });
97
+ if (tar.exitCode !== 0) {
98
+ throw new Error(`[workerstack] tar failed: ${tar.stderr.toString()}`);
99
+ }
100
+ await rm(archive);
101
+ }
102
+ const binary = await findFile(staging, name);
103
+ if (!binary)
104
+ throw new Error(`[workerstack] ${url} has no ${name} file`);
105
+ await chmod(binary, 0o755);
106
+ // Another run may have finished first; keep its copy.
107
+ if (!(await stat(home).catch(() => undefined))) {
108
+ await rename(staging, home);
109
+ }
110
+ }
111
+ finally {
112
+ await rm(staging, { recursive: true, force: true });
113
+ }
114
+ const path = await findFile(home, name);
115
+ if (!path)
116
+ throw new Error(`[workerstack] ${name} is missing from ${home}`);
117
+ return path;
118
+ }
119
+ //# sourceMappingURL=binaries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binaries.js","sourceRoot":"","sources":["../../src/dev/binaries.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,6EAA6E;AAC7E,mCAAmC;AACnC,OAAO,EACL,MAAM,EACN,KAAK,EACL,SAAS,EACT,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,EACN,EAAE,EACF,IAAI,GACL,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAchC,MAAM,IAAI,GAA4B;IACpC,KAAK,EAAE;QACL,OAAO,EAAE,QAAQ;QACjB,MAAM,EAAE,IAAI;QACZ,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE,CACd,oEAAoE,MAAM,KAAK;QACjF,MAAM,EAAE;YACN,sBAAsB,EACpB,kEAAkE;YACpE,2BAA2B,EACzB,kEAAkE;YACpE,0BAA0B,EACxB,kEAAkE;SACrE;KACF;IACD,IAAI,EAAE;QACJ,OAAO,EAAE,UAAU;QACnB,MAAM,EAAE,QAAQ;QAChB,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE,CACd,kGAAkG,MAAM,SAAS;QACnH,MAAM,EAAE;YACN,sBAAsB,EACpB,kEAAkE;YACpE,qBAAqB,EACnB,kEAAkE;YACpE,2BAA2B,EACzB,kEAAkE;YACpE,0BAA0B,EACxB,kEAAkE;SACrE;KACF;CACF,CAAA;AAaD,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,IAAY;IACzD,MAAM,GAAG,GAAG,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAA;IACzE,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAA;IAC1B,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,GAAG,GAAG,eAAe,CAAA;IACvD,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,GAAG,GAAG,oBAAoB,CAAA;IAC3D,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,IAAY;IACtC,OAAO,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CACtC,GAAG,EAAE,CAAC,IAAI,EACV,GAAG,EAAE,CAAC,KAAK,CACZ,CAAA;AACH,CAAC;AAED,KAAK,UAAU,QAAQ,CACrB,GAAW,EACX,IAAY;IAEZ,KAAK,MAAM,KAAK,IAAI,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;QAClC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;YACxC,IAAI,KAAK;gBAAE,OAAO,KAAK,CAAA;QACzB,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAAgB,EAChB,UAA0B,EAAE;IAE5B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAA;IACtC,MAAM,OAAO,GAAG,eAAe,IAAI,CAAC,WAAW,EAAE,MAAM,CAAA;IACvD,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,CAAA;IAC7B,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAA;IAE7B,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,CAAA;IACxC,MAAM,MAAM,GAAG,YAAY,CACzB,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,EACpC,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAC7B,CAAA;IACD,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACzD,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,oBAAoB,IAAI,cAAc,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,aAAa,IAAI,YAAY,OAAO,cAAc,CAC7J,CAAA;IACH,CAAC;IAED,MAAM,QAAQ,GACZ,OAAO,CAAC,QAAQ;QAChB,GAAG,CAAC,qBAAqB;QACzB,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAA;IAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,IAAI,GAAG,CAAC,OAAO,IAAI,MAAM,EAAE,CAAC,CAAA;IAC/D,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;IAChE,IAAI,MAAM,IAAI,CAAC,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;QAAE,OAAO,MAAM,CAAA;IAEzD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IAC3B,OAAO,CAAC,GAAG,EAAE,CAAC,eAAe,IAAI,IAAI,GAAG,CAAC,OAAO,SAAS,GAAG,EAAE,CAAC,CAAA;IAC/D,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC,GAAG,CAAC,CAAA;IACpD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,iBAAiB,GAAG,aAAa,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAA;IACrE,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAA;IAC1D,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACzE,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,iBAAiB,IAAI,gCAAgC,QAAQ,SAAS,MAAM,EAAE,CAC/E,CAAA;IACH,CAAC;IAED,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC1C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,GAAG,CAAC,CAAC,CAAA;IAC1D,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YACxB,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAA;QAC7D,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAA;YAC7C,MAAM,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;YAC/B,MAAM,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAA;YACrE,IAAI,GAAG,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;gBACvB,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;YACvE,CAAC;YACD,MAAM,EAAE,CAAC,OAAO,CAAC,CAAA;QACnB,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;QAC5C,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,GAAG,WAAW,IAAI,OAAO,CAAC,CAAA;QACxE,MAAM,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;QAC1B,sDAAsD;QACtD,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;YAC/C,MAAM,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;QAC7B,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IACrD,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IACvC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,oBAAoB,IAAI,EAAE,CAAC,CAAA;IAC3E,OAAO,IAAI,CAAA;AACb,CAAC","sourcesContent":["// Pinned celld and sqld binaries for `workerstack dev`. The first run\n// downloads them to ~/.cache/workerstack and checks their sha256; an env var\n// selects a system binary instead.\nimport {\n access,\n chmod,\n constants,\n mkdir,\n mkdtemp,\n readdir,\n rename,\n rm,\n stat,\n} from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport type BinaryName = 'celld' | 'sqld'\n\nexport type Pin = {\n version: string\n format: 'gz' | 'tar.xz'\n url: (target: string) => string\n /** sha256 of the downloaded asset, per release target. */\n sha256: Partial<Record<string, string>>\n}\n\nexport type Pins = Partial<Record<BinaryName, Pin>>\n\nconst PINS: Record<BinaryName, Pin> = {\n celld: {\n version: 'v0.6.0',\n format: 'gz',\n url: (target) =>\n `https://github.com/denoland/celld/releases/download/v0.6.0/celld-${target}.gz`,\n sha256: {\n 'aarch64-apple-darwin':\n 'bf6f0c06c4f815eecddf61ae40340935a0dbf76be3d643bf75fdd92bfac425cd',\n 'aarch64-unknown-linux-gnu':\n '3d4945df3abcc6832b6e7fa978b9ee3c26e46a0b7791924843d42c0ed14eff96',\n 'x86_64-unknown-linux-gnu':\n '8f1e18072c234ab75459d4da104c13cebc9b29a3e4a4772086bf985829bea8aa',\n },\n },\n sqld: {\n version: 'v0.24.32',\n format: 'tar.xz',\n url: (target) =>\n `https://github.com/tursodatabase/libsql/releases/download/libsql-server-v0.24.32/libsql-server-${target}.tar.xz`,\n sha256: {\n 'aarch64-apple-darwin':\n 'ced2a9d65a5d4b6bd72c67e98ad6c63139e2a139d91769f07fdd15be935381dd',\n 'x86_64-apple-darwin':\n '461480ea5a17781bab7dd5974aa804007434611baced37b6349c8060d0648e34',\n 'aarch64-unknown-linux-gnu':\n '37f9eee45b388a30192907ecf4565b93df945c079331657073b5b3caf8bb1cd0',\n 'x86_64-unknown-linux-gnu':\n '71720fc8648c19efef416efebd47145ef59b62e198770533530a858e1336879f',\n },\n },\n}\n\nexport type ResolveOptions = {\n env?: Record<string, string | undefined>\n cacheDir?: string\n platform?: string\n arch?: string\n fetch?: (url: string) => Promise<Response>\n log?: (message: string) => void\n /** Replaces the pinned table; for tests. */\n pins?: Pins\n}\n\nexport function binaryTarget(platform: string, arch: string) {\n const cpu = arch === 'arm64' ? 'aarch64' : arch === 'x64' ? 'x86_64' : ''\n if (!cpu) return undefined\n if (platform === 'darwin') return `${cpu}-apple-darwin`\n if (platform === 'linux') return `${cpu}-unknown-linux-gnu`\n return undefined\n}\n\nasync function isExecutable(path: string) {\n return access(path, constants.X_OK).then(\n () => true,\n () => false,\n )\n}\n\nasync function findFile(\n dir: string,\n name: string,\n): Promise<string | undefined> {\n for (const entry of await readdir(dir, { withFileTypes: true })) {\n const path = join(dir, entry.name)\n if (entry.isDirectory()) {\n const found = await findFile(path, name)\n if (found) return found\n } else if (entry.name === name) {\n return path\n }\n }\n return undefined\n}\n\nexport async function resolveBinary(\n name: BinaryName,\n options: ResolveOptions = {},\n): Promise<string> {\n const env = options.env ?? process.env\n const envName = `WORKERSTACK_${name.toUpperCase()}_BIN`\n const override = env[envName]\n if (override) return override\n\n const pin = (options.pins ?? PINS)[name]\n const target = binaryTarget(\n options.platform ?? process.platform,\n options.arch ?? process.arch,\n )\n const checksum = target ? pin?.sha256[target] : undefined\n if (!pin || !target || !checksum) {\n throw new Error(\n `[workerstack] no ${name} build for ${options.platform ?? process.platform} ${options.arch ?? process.arch}; install ${name} and set ${envName} to its path`,\n )\n }\n\n const cacheDir =\n options.cacheDir ??\n env.WORKERSTACK_CACHE_DIR ??\n join(homedir(), '.cache', 'workerstack')\n const home = join(cacheDir, `${name}-${pin.version}-${target}`)\n const cached = await findFile(home, name).catch(() => undefined)\n if (cached && (await isExecutable(cached))) return cached\n\n const url = pin.url(target)\n options.log?.(`downloading ${name} ${pin.version} from ${url}`)\n const response = await (options.fetch ?? fetch)(url)\n if (!response.ok) {\n throw new Error(`[workerstack] ${url} returned ${response.status}`)\n }\n const bytes = new Uint8Array(await response.arrayBuffer())\n const actual = new Bun.CryptoHasher('sha256').update(bytes).digest('hex')\n if (actual !== checksum) {\n throw new Error(\n `[workerstack] ${name} checksum mismatch: expected ${checksum}, got ${actual}`,\n )\n }\n\n await mkdir(cacheDir, { recursive: true })\n const staging = await mkdtemp(join(cacheDir, `.${name}-`))\n try {\n if (pin.format === 'gz') {\n await Bun.write(join(staging, name), Bun.gunzipSync(bytes))\n } else {\n const archive = join(staging, 'asset.tar.xz')\n await Bun.write(archive, bytes)\n const tar = Bun.spawnSync(['tar', '-xJf', archive], { cwd: staging })\n if (tar.exitCode !== 0) {\n throw new Error(`[workerstack] tar failed: ${tar.stderr.toString()}`)\n }\n await rm(archive)\n }\n const binary = await findFile(staging, name)\n if (!binary) throw new Error(`[workerstack] ${url} has no ${name} file`)\n await chmod(binary, 0o755)\n // Another run may have finished first; keep its copy.\n if (!(await stat(home).catch(() => undefined))) {\n await rename(staging, home)\n }\n } finally {\n await rm(staging, { recursive: true, force: true })\n }\n const path = await findFile(home, name)\n if (!path) throw new Error(`[workerstack] ${name} is missing from ${home}`)\n return path\n}\n"]}
@@ -0,0 +1,11 @@
1
+ export declare function parseDotenv(text: string): Record<string, string>;
2
+ export declare function readUserEnv(directory: string): Promise<Record<string, string>>;
3
+ /** A random AUTH_SECRET kept in the dev state dir, so sessions survive restarts. */
4
+ export declare function devSecret(stateDir: string): Promise<string>;
5
+ export declare function devVars(input: {
6
+ userEnv: Record<string, string>;
7
+ databaseUrl: string;
8
+ appUrl: string;
9
+ authSecret: string;
10
+ }): string;
11
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/dev/env.ts"],"names":[],"mappings":"AAKA,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAyBhE;AAED,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CASjC;AAED,oFAAoF;AACpF,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAWjE;AAOD,wBAAgB,OAAO,CAAC,KAAK,EAAE;IAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;CACnB,GAAG,MAAM,CAaT"}
@@ -0,0 +1,71 @@
1
+ // The Worker env for `workerstack dev`: the app's .env files plus the values
2
+ // the dev command owns, written as .dev.vars for celld.
3
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ export function parseDotenv(text) {
6
+ const vars = {};
7
+ for (const raw of text.split(/\r?\n/)) {
8
+ const line = raw.trim();
9
+ if (!line || line.startsWith('#'))
10
+ continue;
11
+ const match = /^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/.exec(line);
12
+ if (!match)
13
+ continue;
14
+ const [, key, rest] = match;
15
+ let value;
16
+ if (rest.startsWith('"')) {
17
+ const end = rest.lastIndexOf('"');
18
+ value = rest
19
+ .slice(1, end > 0 ? end : undefined)
20
+ .replace(/\\(["\\n])/g, (_, c) => (c === 'n' ? '\n' : c));
21
+ }
22
+ else if (rest.startsWith("'")) {
23
+ const end = rest.lastIndexOf("'");
24
+ value = rest.slice(1, end > 0 ? end : undefined);
25
+ }
26
+ else {
27
+ value = rest.replace(/\s+#.*$/, '').trim();
28
+ }
29
+ vars[key] = value;
30
+ }
31
+ return vars;
32
+ }
33
+ export async function readUserEnv(directory) {
34
+ const vars = {};
35
+ for (const name of ['.env', '.env.local']) {
36
+ const text = await readFile(join(directory, name), 'utf8').catch(() => undefined);
37
+ if (text !== undefined)
38
+ Object.assign(vars, parseDotenv(text));
39
+ }
40
+ return vars;
41
+ }
42
+ /** A random AUTH_SECRET kept in the dev state dir, so sessions survive restarts. */
43
+ export async function devSecret(stateDir) {
44
+ const path = join(stateDir, 'auth-secret');
45
+ const existing = (await readFile(path, 'utf8').catch(() => '')).trim();
46
+ if (existing)
47
+ return existing;
48
+ await mkdir(stateDir, { recursive: true });
49
+ const bytes = crypto.getRandomValues(new Uint8Array(32));
50
+ const secret = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
51
+ await writeFile(path, `${secret}\n`, { mode: 0o600 });
52
+ return secret;
53
+ }
54
+ function quote(value) {
55
+ if (/^[A-Za-z0-9_./:@+-]*$/.test(value))
56
+ return value;
57
+ return `"${value.replace(/["\\]/g, '\\$&').replace(/\n/g, '\\n')}"`;
58
+ }
59
+ export function devVars(input) {
60
+ const vars = {
61
+ ...input.userEnv,
62
+ AUTH_SECRET: input.userEnv.AUTH_SECRET || input.authSecret,
63
+ // The dev command picks these; a value from .env would point elsewhere.
64
+ APP_URL: input.appUrl,
65
+ WORKERSTACK_DATABASE_URL: input.databaseUrl,
66
+ };
67
+ return (Object.entries(vars)
68
+ .map(([key, value]) => `${key}=${quote(value)}`)
69
+ .join('\n') + '\n');
70
+ }
71
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/dev/env.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,wDAAwD;AACxD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC7D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,IAAI,GAA2B,EAAE,CAAA;IACvC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAA;QACvB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAQ;QAC3C,MAAM,KAAK,GAAG,qDAAqD,CAAC,IAAI,CACtE,IAAI,CACL,CAAA;QACD,IAAI,CAAC,KAAK;YAAE,SAAQ;QACpB,MAAM,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,KAA4C,CAAA;QAClE,IAAI,KAAa,CAAA;QACjB,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;YACjC,KAAK,GAAG,IAAI;iBACT,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;iBACnC,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACrE,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAChC,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;YACjC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;QAClD,CAAC;aAAM,CAAC;YACN,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;QAC5C,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;IACnB,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,SAAiB;IAEjB,MAAM,IAAI,GAA2B,EAAE,CAAA;IACvC,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,CAC9D,GAAG,EAAE,CAAC,SAAS,CAChB,CAAA;QACD,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAA;IAChE,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAgB;IAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAA;IAC1C,MAAM,QAAQ,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IACtE,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAA;IAC7B,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAA;IACxD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAC3E,EAAE,CACH,CAAA;IACD,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,MAAM,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IACrD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,SAAS,KAAK,CAAC,KAAa;IAC1B,IAAI,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IACrD,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAA;AACrE,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,KAKvB;IACC,MAAM,IAAI,GAA2B;QACnC,GAAG,KAAK,CAAC,OAAO;QAChB,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,WAAW,IAAI,KAAK,CAAC,UAAU;QAC1D,wEAAwE;QACxE,OAAO,EAAE,KAAK,CAAC,MAAM;QACrB,wBAAwB,EAAE,KAAK,CAAC,WAAW;KAC5C,CAAA;IACD,OAAO,CACL,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;SACjB,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;SAC/C,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CACrB,CAAA;AACH,CAAC","sourcesContent":["// The Worker env for `workerstack dev`: the app's .env files plus the values\n// the dev command owns, written as .dev.vars for celld.\nimport { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport { join } from 'node:path'\n\nexport function parseDotenv(text: string): Record<string, string> {\n const vars: Record<string, string> = {}\n for (const raw of text.split(/\\r?\\n/)) {\n const line = raw.trim()\n if (!line || line.startsWith('#')) continue\n const match = /^(?:export\\s+)?([A-Za-z_][A-Za-z0-9_]*)\\s*=\\s*(.*)$/.exec(\n line,\n )\n if (!match) continue\n const [, key, rest] = match as unknown as [string, string, string]\n let value: string\n if (rest.startsWith('\"')) {\n const end = rest.lastIndexOf('\"')\n value = rest\n .slice(1, end > 0 ? end : undefined)\n .replace(/\\\\([\"\\\\n])/g, (_, c: string) => (c === 'n' ? '\\n' : c))\n } else if (rest.startsWith(\"'\")) {\n const end = rest.lastIndexOf(\"'\")\n value = rest.slice(1, end > 0 ? end : undefined)\n } else {\n value = rest.replace(/\\s+#.*$/, '').trim()\n }\n vars[key] = value\n }\n return vars\n}\n\nexport async function readUserEnv(\n directory: string,\n): Promise<Record<string, string>> {\n const vars: Record<string, string> = {}\n for (const name of ['.env', '.env.local']) {\n const text = await readFile(join(directory, name), 'utf8').catch(\n () => undefined,\n )\n if (text !== undefined) Object.assign(vars, parseDotenv(text))\n }\n return vars\n}\n\n/** A random AUTH_SECRET kept in the dev state dir, so sessions survive restarts. */\nexport async function devSecret(stateDir: string): Promise<string> {\n const path = join(stateDir, 'auth-secret')\n const existing = (await readFile(path, 'utf8').catch(() => '')).trim()\n if (existing) return existing\n await mkdir(stateDir, { recursive: true })\n const bytes = crypto.getRandomValues(new Uint8Array(32))\n const secret = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join(\n '',\n )\n await writeFile(path, `${secret}\\n`, { mode: 0o600 })\n return secret\n}\n\nfunction quote(value: string) {\n if (/^[A-Za-z0-9_./:@+-]*$/.test(value)) return value\n return `\"${value.replace(/[\"\\\\]/g, '\\\\$&').replace(/\\n/g, '\\\\n')}\"`\n}\n\nexport function devVars(input: {\n userEnv: Record<string, string>\n databaseUrl: string\n appUrl: string\n authSecret: string\n}): string {\n const vars: Record<string, string> = {\n ...input.userEnv,\n AUTH_SECRET: input.userEnv.AUTH_SECRET || input.authSecret,\n // The dev command picks these; a value from .env would point elsewhere.\n APP_URL: input.appUrl,\n WORKERSTACK_DATABASE_URL: input.databaseUrl,\n }\n return (\n Object.entries(vars)\n .map(([key, value]) => `${key}=${quote(value)}`)\n .join('\\n') + '\\n'\n )\n}\n"]}
@@ -0,0 +1,39 @@
1
+ import { type ProcessSpec } from './processes.js';
2
+ export type DevPlan = {
3
+ appUrl: string;
4
+ databaseUrl: string;
5
+ sqld?: ProcessSpec;
6
+ vite: ProcessSpec;
7
+ };
8
+ export declare function planDev(input: {
9
+ directory: string;
10
+ stateDir: string;
11
+ userEnv: Record<string, string>;
12
+ ports: {
13
+ app: number;
14
+ db: number;
15
+ };
16
+ binaries: {
17
+ sqld: string;
18
+ };
19
+ }): DevPlan;
20
+ /**
21
+ * Removes what a host must not deploy: the Cloudflare plugin's
22
+ * `.assetsignore` (celld rejects it) and every `.dev.vars` (the plugin copies
23
+ * the local one into dist/server). Returns the removed paths.
24
+ */
25
+ export declare function cleanArtifact(directory: string): Promise<string[]>;
26
+ /**
27
+ * The first port from `start` that is free on 127.0.0.1 and on ::1. The
28
+ * browser opens `localhost`, which can resolve to either; Vite on ::1 next to
29
+ * another server on 127.0.0.1 would answer only some requests.
30
+ */
31
+ export declare function firstFreePort(start: number): Promise<number>;
32
+ export declare function runDev(options: {
33
+ directory: string;
34
+ port?: number;
35
+ }): Promise<number>;
36
+ export declare function runBuild(options: {
37
+ directory: string;
38
+ }): Promise<number>;
39
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dev/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAAgB,KAAK,WAAW,EAAE,MAAM,aAAa,CAAA;AAE5D,MAAM,MAAM,OAAO,GAAG;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,IAAI,EAAE,WAAW,CAAA;CAClB,CAAA;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAA;IAClC,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAC3B,GAAG,OAAO,CAmCV;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAiBxE;AA+BD;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKlE;AA2BD,wBAAsB,MAAM,CAAC,OAAO,EAAE;IACpC,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,GAAG,OAAO,CAAC,MAAM,CAAC,CAuHlB;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE;IACtC,SAAS,EAAE,MAAM,CAAA;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiClB"}
@@ -0,0 +1,273 @@
1
+ // `workerstack dev` and `workerstack build`. dev starts sqld and Vite, which
2
+ // runs the Worker (SSR, /api, Durable Objects) in workerd through the
3
+ // Cloudflare plugin; build checks workerstack.blueprint.yaml, writes
4
+ // wrangler.json from it, and builds dist/server and dist/client with Vite.
5
+ import { watch } from 'node:fs';
6
+ import { mkdir, readdir, rm, writeFile } from 'node:fs/promises';
7
+ import { createServer } from 'node:net';
8
+ import { join, relative, resolve, sep } from 'node:path';
9
+ import { fileURLToPath } from 'node:url';
10
+ import { generateBlueprint } from '../blueprint-generator.js';
11
+ import { runWranglerCommand } from '../workers/wrangler.js';
12
+ import { resolveBinary } from './binaries.js';
13
+ import { devSecret, devVars, readUserEnv } from './env.js';
14
+ import { ProcessGroup } from './processes.js';
15
+ export function planDev(input) {
16
+ const { directory, ports, binaries } = input;
17
+ const external = input.userEnv.WORKERSTACK_DATABASE_URL;
18
+ const databaseUrl = external || `http://127.0.0.1:${ports.db}`;
19
+ return {
20
+ // localhost, not 127.0.0.1: auth checks the Origin against APP_URL.
21
+ appUrl: `http://localhost:${ports.app}`,
22
+ databaseUrl,
23
+ sqld: external
24
+ ? undefined
25
+ : {
26
+ name: 'sqld',
27
+ cmd: [
28
+ binaries.sqld,
29
+ '--http-listen-addr',
30
+ `127.0.0.1:${ports.db}`,
31
+ '-d',
32
+ join(input.stateDir, 'db'),
33
+ ],
34
+ cwd: directory,
35
+ },
36
+ vite: {
37
+ name: 'vite',
38
+ cmd: [
39
+ process.execPath,
40
+ 'x',
41
+ '--bun',
42
+ 'vite',
43
+ '--port',
44
+ String(ports.app),
45
+ '--strictPort',
46
+ ],
47
+ cwd: directory,
48
+ },
49
+ };
50
+ }
51
+ /**
52
+ * Removes what a host must not deploy: the Cloudflare plugin's
53
+ * `.assetsignore` (celld rejects it) and every `.dev.vars` (the plugin copies
54
+ * the local one into dist/server). Returns the removed paths.
55
+ */
56
+ export async function cleanArtifact(directory) {
57
+ const dist = join(directory, 'dist');
58
+ const entries = await readdir(dist, {
59
+ recursive: true,
60
+ withFileTypes: true,
61
+ }).catch(() => []);
62
+ const removed = [];
63
+ for (const entry of entries) {
64
+ if (!entry.isFile())
65
+ continue;
66
+ const path = join(entry.parentPath, entry.name);
67
+ const rel = relative(directory, path).split(sep).join('/');
68
+ if (entry.name === '.dev.vars' || rel === 'dist/client/.assetsignore') {
69
+ await rm(path, { force: true });
70
+ removed.push(rel);
71
+ }
72
+ }
73
+ return removed;
74
+ }
75
+ async function hasViteConfig(directory) {
76
+ const files = await readdir(directory);
77
+ return files.some((file) => /^vite\.config\.[cm]?[jt]s$/.test(file));
78
+ }
79
+ async function freePort() {
80
+ return new Promise((resolvePort, reject) => {
81
+ const server = createServer();
82
+ server.listen(0, '127.0.0.1', () => {
83
+ const address = server.address();
84
+ server.close(() => typeof address === 'object' && address
85
+ ? resolvePort(address.port)
86
+ : reject(new Error('no free port')));
87
+ });
88
+ });
89
+ }
90
+ function canListen(port, hostname) {
91
+ try {
92
+ Bun.listen({ hostname, port, socket: { data() { } } }).stop(true);
93
+ return true;
94
+ }
95
+ catch (error) {
96
+ // No IPv6 on this machine: nothing can take the port there either.
97
+ return error.code === 'EADDRNOTAVAIL';
98
+ }
99
+ }
100
+ /**
101
+ * The first port from `start` that is free on 127.0.0.1 and on ::1. The
102
+ * browser opens `localhost`, which can resolve to either; Vite on ::1 next to
103
+ * another server on 127.0.0.1 would answer only some requests.
104
+ */
105
+ export async function firstFreePort(start) {
106
+ for (let port = start; port < start + 100; port++) {
107
+ if (canListen(port, '127.0.0.1') && canListen(port, '::1'))
108
+ return port;
109
+ }
110
+ throw new Error(`[workerstack] no free port from ${start}`);
111
+ }
112
+ async function waitForHealth(url, timeoutMs, cancelled) {
113
+ const deadline = Date.now() + timeoutMs;
114
+ for (;;) {
115
+ if (cancelled())
116
+ return;
117
+ const ok = await fetch(url).then((res) => res.ok, () => false);
118
+ if (ok)
119
+ return;
120
+ if (Date.now() > deadline)
121
+ throw new Error(`timed out waiting for ${url}`);
122
+ await Bun.sleep(200);
123
+ }
124
+ }
125
+ const pushScript = fileURLToPath(new URL(import.meta.url.endsWith('.ts') ? './push.ts' : './push.js', import.meta.url));
126
+ export async function runDev(options) {
127
+ const directory = resolve(options.directory);
128
+ const stateDir = join(directory, '.workerstack', 'dev');
129
+ const group = new ProcessGroup();
130
+ const say = (line) => group.log('dev', line);
131
+ const userEnv = await readUserEnv(directory);
132
+ const external = Boolean(userEnv.WORKERSTACK_DATABASE_URL);
133
+ if (!(await hasViteConfig(directory))) {
134
+ say('vite.config.ts is missing; add workerstack() to it');
135
+ return 1;
136
+ }
137
+ const sqld = external ? '' : await resolveBinary('sqld', { log: say });
138
+ const plan = planDev({
139
+ directory,
140
+ stateDir,
141
+ userEnv,
142
+ ports: {
143
+ // An explicit port is kept, and Vite fails when it is taken.
144
+ app: options.port ??
145
+ (process.env.PORT
146
+ ? Number(process.env.PORT)
147
+ : await firstFreePort(5173)),
148
+ db: await freePort(),
149
+ },
150
+ binaries: { sqld },
151
+ });
152
+ // Children run in their own process groups, so the terminal's Ctrl+C does
153
+ // not reach them; group.stop() passes it on.
154
+ let interrupted = false;
155
+ const interrupt = new Promise((resolveInterrupt) => {
156
+ for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP']) {
157
+ process.once(signal, () => {
158
+ interrupted = true;
159
+ resolveInterrupt();
160
+ });
161
+ }
162
+ });
163
+ const cancelled = () => interrupted;
164
+ let watcher;
165
+ try {
166
+ await mkdir(stateDir, { recursive: true });
167
+ if (plan.sqld) {
168
+ group.start(plan.sqld);
169
+ await waitForHealth(`${plan.databaseUrl}/health`, 20_000, cancelled);
170
+ }
171
+ const authSecret = await devSecret(stateDir);
172
+ await writeFile(join(directory, '.dev.vars'), devVars({
173
+ userEnv,
174
+ databaseUrl: plan.databaseUrl,
175
+ appUrl: plan.appUrl,
176
+ authSecret,
177
+ }));
178
+ const pushEnv = {
179
+ ...userEnv,
180
+ WORKERSTACK_DATABASE_URL: plan.databaseUrl,
181
+ AUTH_SECRET: userEnv.AUTH_SECRET || authSecret,
182
+ APP_URL: plan.appUrl,
183
+ };
184
+ const push = async () => {
185
+ const child = Bun.spawn([process.execPath, pushScript, directory], {
186
+ cwd: directory,
187
+ env: { ...process.env, ...pushEnv },
188
+ stdout: 'pipe',
189
+ stderr: 'pipe',
190
+ });
191
+ const [out, err, code] = await Promise.all([
192
+ new Response(child.stdout).text(),
193
+ new Response(child.stderr).text(),
194
+ child.exited,
195
+ ]);
196
+ // drizzle-kit draws a spinner with escape codes; keep the text only.
197
+ // oxlint-disable-next-line no-control-regex
198
+ const text = `${out}${err}`.replace(/\x1b\[[0-9;]*[A-Za-z]/g, '');
199
+ for (const line of text.trim().split('\n')) {
200
+ if (line.trim())
201
+ group.log('push', line.trim());
202
+ }
203
+ if (code !== 0)
204
+ group.log('push', 'failed; fix the code and save again');
205
+ return code === 0;
206
+ };
207
+ // The first push writes the blueprint and wrangler.json, which the
208
+ // Cloudflare plugin in Vite reads at start.
209
+ await push();
210
+ let timer;
211
+ let running = Promise.resolve(true);
212
+ watcher = watch(join(directory, 'src'), { recursive: true }, (_, file) => {
213
+ if (file && String(file).endsWith('routeTree.gen.ts'))
214
+ return;
215
+ clearTimeout(timer);
216
+ timer = setTimeout(() => {
217
+ running = running.then(push);
218
+ }, 300);
219
+ });
220
+ if (!interrupted)
221
+ group.start(plan.vite);
222
+ await waitForHealth(`${plan.appUrl}/api/health`, 60_000, cancelled).catch(() => say('the Worker did not answer /api/health yet; see the vite log'));
223
+ if (!interrupted)
224
+ say(`App: ${plan.appUrl}`);
225
+ const outcome = await Promise.race([group.exited, interrupt]);
226
+ if (outcome && !interrupted) {
227
+ say(`${outcome.name} exited with code ${outcome.code}; stopping`);
228
+ return 1;
229
+ }
230
+ return 0;
231
+ }
232
+ catch (error) {
233
+ say(error instanceof Error ? error.message : String(error));
234
+ return 1;
235
+ }
236
+ finally {
237
+ watcher?.close();
238
+ await group.stop();
239
+ }
240
+ }
241
+ export async function runBuild(options) {
242
+ const directory = resolve(options.directory);
243
+ try {
244
+ await generateBlueprint({ directory, check: true });
245
+ console.log('workerstack.blueprint.yaml is current');
246
+ await runWranglerCommand({ directory });
247
+ console.log('wrote wrangler.json');
248
+ }
249
+ catch (error) {
250
+ console.error(error instanceof Error ? error.message : String(error));
251
+ return 1;
252
+ }
253
+ if (!(await hasViteConfig(directory))) {
254
+ console.error('[workerstack] vite.config.ts is missing; add workerstack() to it');
255
+ return 1;
256
+ }
257
+ const vite = Bun.spawn([process.execPath, 'x', '--bun', 'vite', 'build'], {
258
+ cwd: directory,
259
+ stdout: 'inherit',
260
+ stderr: 'inherit',
261
+ });
262
+ if ((await vite.exited) !== 0)
263
+ return 1;
264
+ for (const path of await cleanArtifact(directory)) {
265
+ console.log(`removed ${path}`);
266
+ }
267
+ if (!(await Bun.file(join(directory, 'dist/server/index.js')).exists())) {
268
+ console.error('[workerstack] the build did not produce dist/server/index.js');
269
+ return 1;
270
+ }
271
+ return 0;
272
+ }
273
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dev/index.ts"],"names":[],"mappings":"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","sourcesContent":["// `workerstack dev` and `workerstack build`. dev starts sqld and Vite, which\n// runs the Worker (SSR, /api, Durable Objects) in workerd through the\n// Cloudflare plugin; build checks workerstack.blueprint.yaml, writes\n// wrangler.json from it, and builds dist/server and dist/client with Vite.\nimport { watch } from 'node:fs'\nimport { mkdir, readdir, rm, writeFile } from 'node:fs/promises'\nimport { createServer } from 'node:net'\nimport { join, relative, resolve, sep } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nimport { generateBlueprint } from '../blueprint-generator'\nimport { runWranglerCommand } from '../workers/wrangler'\nimport { resolveBinary } from './binaries'\nimport { devSecret, devVars, readUserEnv } from './env'\nimport { ProcessGroup, type ProcessSpec } from './processes'\n\nexport type DevPlan = {\n appUrl: string\n databaseUrl: string\n sqld?: ProcessSpec\n vite: ProcessSpec\n}\n\nexport function planDev(input: {\n directory: string\n stateDir: string\n userEnv: Record<string, string>\n ports: { app: number; db: number }\n binaries: { sqld: string }\n}): DevPlan {\n const { directory, ports, binaries } = input\n const external = input.userEnv.WORKERSTACK_DATABASE_URL\n const databaseUrl = external || `http://127.0.0.1:${ports.db}`\n return {\n // localhost, not 127.0.0.1: auth checks the Origin against APP_URL.\n appUrl: `http://localhost:${ports.app}`,\n databaseUrl,\n sqld: external\n ? undefined\n : {\n name: 'sqld',\n cmd: [\n binaries.sqld,\n '--http-listen-addr',\n `127.0.0.1:${ports.db}`,\n '-d',\n join(input.stateDir, 'db'),\n ],\n cwd: directory,\n },\n vite: {\n name: 'vite',\n cmd: [\n process.execPath,\n 'x',\n '--bun',\n 'vite',\n '--port',\n String(ports.app),\n '--strictPort',\n ],\n cwd: directory,\n },\n }\n}\n\n/**\n * Removes what a host must not deploy: the Cloudflare plugin's\n * `.assetsignore` (celld rejects it) and every `.dev.vars` (the plugin copies\n * the local one into dist/server). Returns the removed paths.\n */\nexport async function cleanArtifact(directory: string): Promise<string[]> {\n const dist = join(directory, 'dist')\n const entries = await readdir(dist, {\n recursive: true,\n withFileTypes: true,\n }).catch(() => [])\n const removed: string[] = []\n for (const entry of entries) {\n if (!entry.isFile()) continue\n const path = join(entry.parentPath, entry.name)\n const rel = relative(directory, path).split(sep).join('/')\n if (entry.name === '.dev.vars' || rel === 'dist/client/.assetsignore') {\n await rm(path, { force: true })\n removed.push(rel)\n }\n }\n return removed\n}\n\nasync function hasViteConfig(directory: string) {\n const files = await readdir(directory)\n return files.some((file) => /^vite\\.config\\.[cm]?[jt]s$/.test(file))\n}\n\nasync function freePort(): Promise<number> {\n return new Promise((resolvePort, reject) => {\n const server = createServer()\n server.listen(0, '127.0.0.1', () => {\n const address = server.address()\n server.close(() =>\n typeof address === 'object' && address\n ? resolvePort(address.port)\n : reject(new Error('no free port')),\n )\n })\n })\n}\n\nfunction canListen(port: number, hostname: string): boolean {\n try {\n Bun.listen({ hostname, port, socket: { data() {} } }).stop(true)\n return true\n } catch (error) {\n // No IPv6 on this machine: nothing can take the port there either.\n return (error as { code?: string }).code === 'EADDRNOTAVAIL'\n }\n}\n\n/**\n * The first port from `start` that is free on 127.0.0.1 and on ::1. The\n * browser opens `localhost`, which can resolve to either; Vite on ::1 next to\n * another server on 127.0.0.1 would answer only some requests.\n */\nexport async function firstFreePort(start: number): Promise<number> {\n for (let port = start; port < start + 100; port++) {\n if (canListen(port, '127.0.0.1') && canListen(port, '::1')) return port\n }\n throw new Error(`[workerstack] no free port from ${start}`)\n}\n\nasync function waitForHealth(\n url: string,\n timeoutMs: number,\n cancelled: () => boolean,\n) {\n const deadline = Date.now() + timeoutMs\n for (;;) {\n if (cancelled()) return\n const ok = await fetch(url).then(\n (res) => res.ok,\n () => false,\n )\n if (ok) return\n if (Date.now() > deadline) throw new Error(`timed out waiting for ${url}`)\n await Bun.sleep(200)\n }\n}\n\nconst pushScript = fileURLToPath(\n new URL(\n import.meta.url.endsWith('.ts') ? './push.ts' : './push.js',\n import.meta.url,\n ),\n)\n\nexport async function runDev(options: {\n directory: string\n port?: number\n}): Promise<number> {\n const directory = resolve(options.directory)\n const stateDir = join(directory, '.workerstack', 'dev')\n const group = new ProcessGroup()\n const say = (line: string) => group.log('dev', line)\n\n const userEnv = await readUserEnv(directory)\n const external = Boolean(userEnv.WORKERSTACK_DATABASE_URL)\n if (!(await hasViteConfig(directory))) {\n say('vite.config.ts is missing; add workerstack() to it')\n return 1\n }\n const sqld = external ? '' : await resolveBinary('sqld', { log: say })\n const plan = planDev({\n directory,\n stateDir,\n userEnv,\n ports: {\n // An explicit port is kept, and Vite fails when it is taken.\n app:\n options.port ??\n (process.env.PORT\n ? Number(process.env.PORT)\n : await firstFreePort(5173)),\n db: await freePort(),\n },\n binaries: { sqld },\n })\n\n // Children run in their own process groups, so the terminal's Ctrl+C does\n // not reach them; group.stop() passes it on.\n let interrupted = false\n const interrupt = new Promise<void>((resolveInterrupt) => {\n for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP'] as const) {\n process.once(signal, () => {\n interrupted = true\n resolveInterrupt()\n })\n }\n })\n const cancelled = () => interrupted\n let watcher: ReturnType<typeof watch> | undefined\n\n try {\n await mkdir(stateDir, { recursive: true })\n if (plan.sqld) {\n group.start(plan.sqld)\n await waitForHealth(`${plan.databaseUrl}/health`, 20_000, cancelled)\n }\n const authSecret = await devSecret(stateDir)\n await writeFile(\n join(directory, '.dev.vars'),\n devVars({\n userEnv,\n databaseUrl: plan.databaseUrl,\n appUrl: plan.appUrl,\n authSecret,\n }),\n )\n const pushEnv = {\n ...userEnv,\n WORKERSTACK_DATABASE_URL: plan.databaseUrl,\n AUTH_SECRET: userEnv.AUTH_SECRET || authSecret,\n APP_URL: plan.appUrl,\n }\n const push = async () => {\n const child = Bun.spawn([process.execPath, pushScript, directory], {\n cwd: directory,\n env: { ...process.env, ...pushEnv },\n stdout: 'pipe',\n stderr: 'pipe',\n })\n const [out, err, code] = await Promise.all([\n new Response(child.stdout).text(),\n new Response(child.stderr).text(),\n child.exited,\n ])\n // drizzle-kit draws a spinner with escape codes; keep the text only.\n // oxlint-disable-next-line no-control-regex\n const text = `${out}${err}`.replace(/\\x1b\\[[0-9;]*[A-Za-z]/g, '')\n for (const line of text.trim().split('\\n')) {\n if (line.trim()) group.log('push', line.trim())\n }\n if (code !== 0) group.log('push', 'failed; fix the code and save again')\n return code === 0\n }\n // The first push writes the blueprint and wrangler.json, which the\n // Cloudflare plugin in Vite reads at start.\n await push()\n\n let timer: ReturnType<typeof setTimeout> | undefined\n let running = Promise.resolve(true)\n watcher = watch(join(directory, 'src'), { recursive: true }, (_, file) => {\n if (file && String(file).endsWith('routeTree.gen.ts')) return\n clearTimeout(timer)\n timer = setTimeout(() => {\n running = running.then(push)\n }, 300)\n })\n\n if (!interrupted) group.start(plan.vite)\n await waitForHealth(`${plan.appUrl}/api/health`, 60_000, cancelled).catch(\n () => say('the Worker did not answer /api/health yet; see the vite log'),\n )\n if (!interrupted) say(`App: ${plan.appUrl}`)\n\n const outcome = await Promise.race([group.exited, interrupt])\n if (outcome && !interrupted) {\n say(`${outcome.name} exited with code ${outcome.code}; stopping`)\n return 1\n }\n return 0\n } catch (error) {\n say(error instanceof Error ? error.message : String(error))\n return 1\n } finally {\n watcher?.close()\n await group.stop()\n }\n}\n\nexport async function runBuild(options: {\n directory: string\n}): Promise<number> {\n const directory = resolve(options.directory)\n try {\n await generateBlueprint({ directory, check: true })\n console.log('workerstack.blueprint.yaml is current')\n await runWranglerCommand({ directory })\n console.log('wrote wrangler.json')\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error))\n return 1\n }\n if (!(await hasViteConfig(directory))) {\n console.error(\n '[workerstack] vite.config.ts is missing; add workerstack() to it',\n )\n return 1\n }\n const vite = Bun.spawn([process.execPath, 'x', '--bun', 'vite', 'build'], {\n cwd: directory,\n stdout: 'inherit',\n stderr: 'inherit',\n })\n if ((await vite.exited) !== 0) return 1\n for (const path of await cleanArtifact(directory)) {\n console.log(`removed ${path}`)\n }\n if (!(await Bun.file(join(directory, 'dist/server/index.js')).exists())) {\n console.error(\n '[workerstack] the build did not produce dist/server/index.js',\n )\n return 1\n }\n return 0\n}\n"]}