dotdo 0.0.2 → 0.1.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 (313) hide show
  1. package/cli/README.md +238 -0
  2. package/cli/agent.ts +72 -0
  3. package/cli/bin.js +44 -0
  4. package/cli/bin.ts +38 -0
  5. package/cli/build.ts +157 -0
  6. package/cli/commands/auth/login.ts +14 -0
  7. package/cli/commands/auth/logout.ts +6 -0
  8. package/cli/commands/auth/whoami.ts +16 -0
  9. package/cli/commands/deploy-multi.ts +245 -0
  10. package/cli/commands/dev/deploy.ts +100 -0
  11. package/cli/commands/dev/dev.ts +95 -0
  12. package/cli/commands/dev/logs.ts +91 -0
  13. package/cli/commands/dev-local.ts +88 -0
  14. package/cli/commands/do-ops.ts +314 -0
  15. package/cli/commands/index.ts +100 -0
  16. package/cli/commands/init.ts +247 -0
  17. package/cli/commands/introspect/emitter.ts +315 -0
  18. package/cli/commands/introspect/index.ts +193 -0
  19. package/cli/commands/link.ts +598 -0
  20. package/cli/commands/snippets.ts +415 -0
  21. package/cli/commands/tunnel.ts +239 -0
  22. package/cli/device-auth.ts +289 -0
  23. package/cli/fallback.ts +12 -0
  24. package/cli/index.ts +121 -0
  25. package/cli/main.ts +246 -0
  26. package/cli/mcp-stdio.ts +790 -0
  27. package/cli/package.json +62 -0
  28. package/cli/runtime/do-registry.ts +193 -0
  29. package/cli/runtime/embedded-db.ts +344 -0
  30. package/cli/runtime/index.ts +9 -0
  31. package/cli/runtime/miniflare-adapter.ts +162 -0
  32. package/cli/sandbox.ts +82 -0
  33. package/cli/src/args.ts +174 -0
  34. package/cli/src/auth.ts +55 -0
  35. package/cli/src/commands/call.ts +84 -0
  36. package/cli/src/commands/charge.ts +96 -0
  37. package/cli/src/commands/config.ts +115 -0
  38. package/cli/src/commands/email.ts +112 -0
  39. package/cli/src/commands/llm.ts +115 -0
  40. package/cli/src/commands/queue.ts +134 -0
  41. package/cli/src/commands/text.ts +86 -0
  42. package/cli/src/config.ts +185 -0
  43. package/cli/src/output.ts +246 -0
  44. package/cli/src/rpc.ts +192 -0
  45. package/cli/utils/config.ts +282 -0
  46. package/cli/utils/detect.ts +73 -0
  47. package/cli/utils/index.ts +15 -0
  48. package/cli/utils/logger.ts +232 -0
  49. package/dist/ai/template-literals.js +2 -2
  50. package/dist/ai/template-literals.js.map +1 -1
  51. package/dist/api/middleware/auth.js +3 -2
  52. package/dist/api/middleware/auth.js.map +1 -1
  53. package/dist/db/iceberg/inverted-index.js +1 -1
  54. package/dist/db/iceberg/inverted-index.js.map +1 -1
  55. package/dist/db/iceberg/puffin.js.map +1 -1
  56. package/dist/db/json-indexes.js.map +1 -1
  57. package/dist/db/objects.js.map +1 -1
  58. package/dist/db/primitives/dag-scheduler/index.js +1 -1
  59. package/dist/db/primitives/dag-scheduler/index.js.map +1 -1
  60. package/dist/db/primitives/observability.js.map +1 -1
  61. package/dist/db/primitives/schema-evolution.js.map +1 -1
  62. package/dist/db/primitives/temporal-store.js.map +1 -1
  63. package/dist/db/primitives/typed-column-store.js.map +1 -1
  64. package/dist/db/primitives/utils/duration.js.map +1 -1
  65. package/dist/db/primitives/utils/murmur3.js +12 -14
  66. package/dist/db/primitives/utils/murmur3.js.map +1 -1
  67. package/dist/db/primitives/window-manager.js.map +1 -1
  68. package/dist/db/stores.js.map +1 -1
  69. package/dist/db/things.js.map +1 -1
  70. package/dist/lib/DODispatcher.js +2 -2
  71. package/dist/lib/DODispatcher.js.map +1 -1
  72. package/dist/lib/auto-wiring.js.map +1 -1
  73. package/dist/lib/channels/email.js +1 -1
  74. package/dist/lib/channels/email.js.map +1 -1
  75. package/dist/lib/channels/slack-blockkit.js.map +1 -1
  76. package/dist/lib/cloudflare/ai.js +1 -1
  77. package/dist/lib/cloudflare/ai.js.map +1 -1
  78. package/dist/lib/cloudflare/kv.js +1 -1
  79. package/dist/lib/cloudflare/kv.js.map +1 -1
  80. package/dist/lib/cloudflare/r2.js +3 -3
  81. package/dist/lib/cloudflare/r2.js.map +1 -1
  82. package/dist/lib/cloudflare/vectorize.js.map +1 -1
  83. package/dist/lib/cloudflare/workflows.js.map +1 -1
  84. package/dist/lib/executors/AgenticFunctionExecutor.js.map +1 -1
  85. package/dist/lib/executors/CodeFunctionExecutor.js.map +1 -1
  86. package/dist/lib/executors/GenerativeFunctionExecutor.js.map +1 -1
  87. package/dist/lib/executors/HumanFunctionExecutor.js +1 -1
  88. package/dist/lib/executors/HumanFunctionExecutor.js.map +1 -1
  89. package/dist/lib/executors/ParallelStepExecutor.js.map +1 -1
  90. package/dist/lib/experiments.js.map +1 -1
  91. package/dist/lib/flags/store.js.map +1 -1
  92. package/dist/lib/functions/FunctionComposition.js.map +1 -1
  93. package/dist/lib/functions/FunctionMiddleware.js.map +1 -1
  94. package/dist/lib/functions/FunctionRegistry.js.map +1 -1
  95. package/dist/lib/humans/templates.js.map +1 -1
  96. package/dist/lib/identity.js +2 -2
  97. package/dist/lib/identity.js.map +1 -1
  98. package/dist/lib/logging/index.js.map +1 -1
  99. package/dist/lib/mixins/bash.js +1 -73
  100. package/dist/lib/mixins/bash.js.map +1 -1
  101. package/dist/lib/mixins/git.js +0 -5
  102. package/dist/lib/mixins/git.js.map +1 -1
  103. package/dist/lib/mixins/npm.js.map +1 -1
  104. package/dist/lib/noun-id.js.map +1 -1
  105. package/dist/lib/rate-limit/sliding-window.js.map +1 -1
  106. package/dist/lib/rpc/bindings.js.map +1 -1
  107. package/dist/lib/safe-stringify.js.map +1 -1
  108. package/dist/lib/sandbox/miniflare-sandbox.js.map +1 -1
  109. package/dist/lib/sqids.js.map +1 -1
  110. package/dist/lib/sql/adapters/node-sql-parser.js.map +1 -1
  111. package/dist/lib/sql/adapters/pgsql-parser.js +19 -18
  112. package/dist/lib/sql/adapters/pgsql-parser.js.map +1 -1
  113. package/dist/metrics/hunch.js.map +1 -1
  114. package/dist/objects/API.js +1 -1
  115. package/dist/objects/API.js.map +1 -1
  116. package/dist/objects/Agent.js.map +1 -1
  117. package/dist/objects/Browser.js.map +1 -1
  118. package/dist/objects/CLI.js.map +1 -1
  119. package/dist/objects/DOBase.js.map +1 -1
  120. package/dist/objects/DOCache.js +153 -0
  121. package/dist/objects/DOCache.js.map +1 -0
  122. package/dist/objects/DOFull.js.map +1 -1
  123. package/dist/objects/Entity.js.map +1 -1
  124. package/dist/objects/Human.js.map +1 -1
  125. package/dist/objects/IcebergMetadataDO.js.map +1 -1
  126. package/dist/objects/IntegrationsDO.js.map +1 -1
  127. package/dist/objects/ObservabilityBroadcaster.js.map +1 -1
  128. package/dist/objects/Package.js.map +1 -1
  129. package/dist/objects/Product.js +1 -1
  130. package/dist/objects/Product.js.map +1 -1
  131. package/dist/objects/SaaS.js.map +1 -1
  132. package/dist/objects/SandboxDO.js.map +1 -1
  133. package/dist/objects/Service.js.map +1 -1
  134. package/dist/objects/VectorShardDO.js +9 -7
  135. package/dist/objects/VectorShardDO.js.map +1 -1
  136. package/dist/objects/Workflow.js.map +1 -1
  137. package/dist/objects/WorkflowFactory.js.map +1 -1
  138. package/dist/objects/WorkflowRuntime.js.map +1 -1
  139. package/dist/objects/lifecycle/Branch.js.map +1 -1
  140. package/dist/objects/lifecycle/Clone.js +1 -1
  141. package/dist/objects/lifecycle/Clone.js.map +1 -1
  142. package/dist/objects/lifecycle/Compact.js.map +1 -1
  143. package/dist/objects/lifecycle/Shard.js.map +1 -1
  144. package/dist/objects/persistence/checkpoint-manager.js.map +1 -1
  145. package/dist/objects/persistence/migration-runner.js.map +1 -1
  146. package/dist/objects/persistence/replication-manager.js +2 -2
  147. package/dist/objects/persistence/replication-manager.js.map +1 -1
  148. package/dist/objects/persistence/tiered-storage-manager.js.map +1 -1
  149. package/dist/objects/persistence/wal-manager.js.map +1 -1
  150. package/dist/objects/transport/auth-layer.js.map +1 -1
  151. package/dist/objects/transport/chain.js.map +1 -1
  152. package/dist/objects/transport/mcp-server.js +7 -6
  153. package/dist/objects/transport/mcp-server.js.map +1 -1
  154. package/dist/objects/transport/rest-autowire.js +3 -2
  155. package/dist/objects/transport/rest-autowire.js.map +1 -1
  156. package/dist/objects/transport/rest-router.js.map +1 -1
  157. package/dist/objects/transport/rpc-server.js +18 -15
  158. package/dist/objects/transport/rpc-server.js.map +1 -1
  159. package/dist/objects/transport/shared.js +2 -1
  160. package/dist/objects/transport/shared.js.map +1 -1
  161. package/dist/snippets/artifacts-ingest.js.map +1 -1
  162. package/dist/snippets/artifacts-serve.js.map +1 -1
  163. package/dist/snippets/search.js.map +1 -1
  164. package/dist/workflows/ScheduleManager.js.map +1 -1
  165. package/dist/workflows/StepResultStorage.js.map +1 -1
  166. package/dist/workflows/WaitForEventManager.js.map +1 -1
  167. package/dist/workflows/compat/backends/cloudflare-workflows.js.map +1 -1
  168. package/dist/workflows/compat/inngest/index.js.map +1 -1
  169. package/dist/workflows/compat/qstash/index.js.map +1 -1
  170. package/dist/workflows/compat/temporal/client.js.map +1 -1
  171. package/dist/workflows/compat/temporal/index.js.map +1 -1
  172. package/dist/workflows/compat/trigger/index.js.map +1 -1
  173. package/dist/workflows/compat/utils/index.js.map +1 -1
  174. package/dist/workflows/context/correlation.js +2 -2
  175. package/dist/workflows/context/correlation.js.map +1 -1
  176. package/dist/workflows/context/experiment.js +1 -1
  177. package/dist/workflows/context/experiment.js.map +1 -1
  178. package/dist/workflows/context/flag.js +1 -1
  179. package/dist/workflows/context/flag.js.map +1 -1
  180. package/dist/workflows/context/measure.js +1 -1
  181. package/dist/workflows/context/measure.js.map +1 -1
  182. package/dist/workflows/context/rate-limit.js.map +1 -1
  183. package/dist/workflows/data/entity-events/entity-events.js.map +1 -1
  184. package/dist/workflows/data/experiment/index.js.map +1 -1
  185. package/dist/workflows/data/goal/context.js +1 -1
  186. package/dist/workflows/data/goal/context.js.map +1 -1
  187. package/dist/workflows/data/measure/index.js +1 -1
  188. package/dist/workflows/data/measure/index.js.map +1 -1
  189. package/dist/workflows/data/stream/index.js +10 -76
  190. package/dist/workflows/data/stream/index.js.map +1 -1
  191. package/dist/workflows/data/track/context.js.map +1 -1
  192. package/dist/workflows/data/view/context.js.map +1 -1
  193. package/dist/workflows/domain.js.map +1 -1
  194. package/dist/workflows/flags.js +1 -1
  195. package/dist/workflows/flags.js.map +1 -1
  196. package/dist/workflows/hash.js.map +1 -1
  197. package/dist/workflows/on.js +1 -1
  198. package/dist/workflows/on.js.map +1 -1
  199. package/dist/workflows/schedule-builder.js.map +1 -1
  200. package/dist/workflows/visibility/index.js +0 -2
  201. package/dist/workflows/visibility/index.js.map +1 -1
  202. package/dist/workflows/visibility/query-parser.js.map +1 -1
  203. package/package.json +18 -3
  204. package/dist/api/analytics/router.js +0 -601
  205. package/dist/api/analytics/router.js.map +0 -1
  206. package/dist/api/index.js +0 -158
  207. package/dist/api/index.js.map +0 -1
  208. package/dist/api/middleware/error-handling.js +0 -176
  209. package/dist/api/middleware/error-handling.js.map +0 -1
  210. package/dist/api/middleware/request-id.js +0 -21
  211. package/dist/api/middleware/request-id.js.map +0 -1
  212. package/dist/api/pages.js +0 -1180
  213. package/dist/api/pages.js.map +0 -1
  214. package/dist/api/routes/api.js +0 -612
  215. package/dist/api/routes/api.js.map +0 -1
  216. package/dist/api/routes/browsers.js +0 -471
  217. package/dist/api/routes/browsers.js.map +0 -1
  218. package/dist/api/routes/do.js +0 -188
  219. package/dist/api/routes/do.js.map +0 -1
  220. package/dist/api/routes/mcp.js +0 -459
  221. package/dist/api/routes/mcp.js.map +0 -1
  222. package/dist/api/routes/obs.js +0 -445
  223. package/dist/api/routes/obs.js.map +0 -1
  224. package/dist/api/routes/openapi.js +0 -794
  225. package/dist/api/routes/openapi.js.map +0 -1
  226. package/dist/api/routes/rpc.js +0 -1103
  227. package/dist/api/routes/rpc.js.map +0 -1
  228. package/dist/api/routes/sandboxes.js +0 -389
  229. package/dist/api/routes/sandboxes.js.map +0 -1
  230. package/dist/api/test-do.js +0 -38
  231. package/dist/api/test-do.js.map +0 -1
  232. package/dist/api/types.js +0 -11
  233. package/dist/api/types.js.map +0 -1
  234. package/dist/cli/bin.js +0 -2
  235. package/dist/cli/main.js +0 -52342
  236. package/dist/do/bash.js +0 -35
  237. package/dist/do/bash.js.map +0 -1
  238. package/dist/do/fs.js +0 -25
  239. package/dist/do/fs.js.map +0 -1
  240. package/dist/do/full.js +0 -61
  241. package/dist/do/full.js.map +0 -1
  242. package/dist/do/git.js +0 -28
  243. package/dist/do/git.js.map +0 -1
  244. package/dist/do/index.js +0 -52
  245. package/dist/do/index.js.map +0 -1
  246. package/dist/lib/agent/tools/bash.js +0 -336
  247. package/dist/lib/agent/tools/bash.js.map +0 -1
  248. package/dist/lib/agent/tools/edit.js +0 -157
  249. package/dist/lib/agent/tools/edit.js.map +0 -1
  250. package/dist/lib/agent/tools/glob.js +0 -137
  251. package/dist/lib/agent/tools/glob.js.map +0 -1
  252. package/dist/lib/agent/tools/grep.js +0 -315
  253. package/dist/lib/agent/tools/grep.js.map +0 -1
  254. package/dist/lib/agent/tools/index.js +0 -71
  255. package/dist/lib/agent/tools/index.js.map +0 -1
  256. package/dist/lib/agent/tools/read.js +0 -212
  257. package/dist/lib/agent/tools/read.js.map +0 -1
  258. package/dist/lib/agent/tools/types.js +0 -197
  259. package/dist/lib/agent/tools/types.js.map +0 -1
  260. package/dist/lib/agent/tools/write.js +0 -159
  261. package/dist/lib/agent/tools/write.js.map +0 -1
  262. package/dist/lib/mixins/index.js +0 -29
  263. package/dist/lib/mixins/index.js.map +0 -1
  264. package/dist/primitives/bashx/src/ast/analyze.js +0 -1472
  265. package/dist/primitives/bashx/src/ast/analyze.js.map +0 -1
  266. package/dist/primitives/bashx/src/ast/parser.js +0 -1488
  267. package/dist/primitives/bashx/src/ast/parser.js.map +0 -1
  268. package/dist/primitives/bashx/src/do/commands/crypto.js +0 -1954
  269. package/dist/primitives/bashx/src/do/commands/crypto.js.map +0 -1
  270. package/dist/primitives/bashx/src/do/commands/data-processing.js +0 -1812
  271. package/dist/primitives/bashx/src/do/commands/data-processing.js.map +0 -1
  272. package/dist/primitives/bashx/src/do/commands/extended-utils.js +0 -804
  273. package/dist/primitives/bashx/src/do/commands/extended-utils.js.map +0 -1
  274. package/dist/primitives/bashx/src/do/commands/math-control.js +0 -1122
  275. package/dist/primitives/bashx/src/do/commands/math-control.js.map +0 -1
  276. package/dist/primitives/bashx/src/do/commands/posix-utils.js +0 -1015
  277. package/dist/primitives/bashx/src/do/commands/posix-utils.js.map +0 -1
  278. package/dist/primitives/bashx/src/do/commands/system-utils.js +0 -687
  279. package/dist/primitives/bashx/src/do/commands/system-utils.js.map +0 -1
  280. package/dist/primitives/bashx/src/do/commands/test-command.js +0 -523
  281. package/dist/primitives/bashx/src/do/commands/test-command.js.map +0 -1
  282. package/dist/primitives/bashx/src/do/commands/text-processing.js +0 -1550
  283. package/dist/primitives/bashx/src/do/commands/text-processing.js.map +0 -1
  284. package/dist/primitives/bashx/src/do/container-executor.js +0 -429
  285. package/dist/primitives/bashx/src/do/container-executor.js.map +0 -1
  286. package/dist/primitives/bashx/src/do/index.js +0 -668
  287. package/dist/primitives/bashx/src/do/index.js.map +0 -1
  288. package/dist/primitives/bashx/src/do/tiered-executor.js +0 -2647
  289. package/dist/primitives/bashx/src/do/tiered-executor.js.map +0 -1
  290. package/dist/primitives/bashx/src/do/worker.js +0 -352
  291. package/dist/primitives/bashx/src/do/worker.js.map +0 -1
  292. package/dist/primitives/bashx/src/types.js +0 -10
  293. package/dist/primitives/bashx/src/types.js.map +0 -1
  294. package/dist/primitives/fsx/core/backend.js +0 -480
  295. package/dist/primitives/fsx/core/backend.js.map +0 -1
  296. package/dist/primitives/fsx/core/constants.js +0 -140
  297. package/dist/primitives/fsx/core/constants.js.map +0 -1
  298. package/dist/primitives/fsx/core/fsx.js +0 -1184
  299. package/dist/primitives/fsx/core/fsx.js.map +0 -1
  300. package/dist/primitives/fsx/core/glob/glob.js +0 -438
  301. package/dist/primitives/fsx/core/glob/glob.js.map +0 -1
  302. package/dist/primitives/fsx/core/glob/index.js +0 -8
  303. package/dist/primitives/fsx/core/glob/index.js.map +0 -1
  304. package/dist/primitives/fsx/core/glob/match.js +0 -392
  305. package/dist/primitives/fsx/core/glob/match.js.map +0 -1
  306. package/dist/primitives/fsx/core/types.js +0 -307
  307. package/dist/primitives/fsx/core/types.js.map +0 -1
  308. package/dist/sdk/capnweb-compat.js +0 -42
  309. package/dist/sdk/capnweb-compat.js.map +0 -1
  310. package/dist/sdk/client.js +0 -20
  311. package/dist/sdk/client.js.map +0 -1
  312. package/dist/sdk/index.js +0 -17
  313. package/dist/sdk/index.js.map +0 -1
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@dotdo/cli",
3
+ "version": "0.1.0",
4
+ "description": "Self-contained CLI for Durable Objects development",
5
+ "type": "module",
6
+ "main": "./main.ts",
7
+ "bin": {
8
+ "dotdo": "./main.ts",
9
+ "do": "./main.ts"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "commands",
14
+ "runtime",
15
+ "utils",
16
+ "main.ts",
17
+ "build.ts"
18
+ ],
19
+ "scripts": {
20
+ "start": "bun run main.ts",
21
+ "build": "bun build main.ts --compile --minify --outfile dotdo",
22
+ "build:ts": "bun run build.ts",
23
+ "build:all": "bun run build.ts",
24
+ "dev": "bun run main.ts dev",
25
+ "test": "bun test",
26
+ "typecheck": "tsc --noEmit"
27
+ },
28
+ "dependencies": {
29
+ "commander": "^14.0.2",
30
+ "miniflare": "^3.20241205.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/bun": "^1.1.14",
34
+ "@types/better-sqlite3": "^7.6.13",
35
+ "typescript": "^5.7.0"
36
+ },
37
+ "peerDependencies": {
38
+ "better-sqlite3": "^11.0.0"
39
+ },
40
+ "peerDependenciesMeta": {
41
+ "better-sqlite3": {
42
+ "optional": true
43
+ }
44
+ },
45
+ "engines": {
46
+ "bun": ">=1.1.0"
47
+ },
48
+ "keywords": [
49
+ "cli",
50
+ "durable-objects",
51
+ "cloudflare",
52
+ "workers",
53
+ "bun"
54
+ ],
55
+ "author": "dotdo team",
56
+ "license": "MIT",
57
+ "repository": {
58
+ "type": "git",
59
+ "url": "https://github.com/dot-do/dotdo",
60
+ "directory": "cli"
61
+ }
62
+ }
@@ -0,0 +1,193 @@
1
+ /**
2
+ * DO Registry
3
+ *
4
+ * Discovers, tracks, and manages Durable Object classes in the project.
5
+ * Scans source files for DO class definitions and maintains a registry.
6
+ */
7
+
8
+ import { Logger, createLogger } from '../utils/logger'
9
+ import * as fs from 'fs'
10
+ import * as path from 'path'
11
+
12
+ export interface DOClassInfo {
13
+ className: string
14
+ filePath: string
15
+ exports: string[]
16
+ hasAlarm?: boolean
17
+ hasFetch?: boolean
18
+ hasWebSocket?: boolean
19
+ }
20
+
21
+ export interface DORegistryOptions {
22
+ logger?: Logger
23
+ }
24
+
25
+ /**
26
+ * Registry for discovering and managing Durable Object classes
27
+ */
28
+ export class DORegistry {
29
+ private logger: Logger
30
+ private classes: Map<string, DOClassInfo> = new Map()
31
+
32
+ constructor(options: DORegistryOptions = {}) {
33
+ this.logger = options.logger ?? createLogger('registry')
34
+ }
35
+
36
+ /**
37
+ * Discover DO classes from source directory
38
+ */
39
+ async discover(srcDir: string): Promise<Record<string, { className: string }>> {
40
+ this.logger.debug(`Scanning ${srcDir} for Durable Objects...`)
41
+
42
+ const files = await this.findTypeScriptFiles(srcDir)
43
+ const discovered: Record<string, { className: string }> = {}
44
+
45
+ for (const file of files) {
46
+ const classes = await this.extractDOClasses(file)
47
+ for (const cls of classes) {
48
+ this.classes.set(cls.className, cls)
49
+ discovered[cls.className] = { className: cls.className }
50
+ this.logger.debug(`Found DO: ${cls.className} in ${file}`)
51
+ }
52
+ }
53
+
54
+ this.logger.info(`Discovered ${Object.keys(discovered).length} Durable Objects`)
55
+ return discovered
56
+ }
57
+
58
+ /**
59
+ * Find all TypeScript files in directory recursively
60
+ */
61
+ private async findTypeScriptFiles(dir: string): Promise<string[]> {
62
+ const results: string[] = []
63
+
64
+ if (!fs.existsSync(dir)) {
65
+ return results
66
+ }
67
+
68
+ const entries = fs.readdirSync(dir, { withFileTypes: true })
69
+
70
+ for (const entry of entries) {
71
+ const fullPath = path.join(dir, entry.name)
72
+
73
+ // Skip node_modules and hidden directories
74
+ if (entry.isDirectory()) {
75
+ if (entry.name.startsWith('.') || entry.name === 'node_modules' || entry.name === 'dist') {
76
+ continue
77
+ }
78
+ results.push(...await this.findTypeScriptFiles(fullPath))
79
+ } else if (entry.name.endsWith('.ts') && !entry.name.endsWith('.d.ts')) {
80
+ results.push(fullPath)
81
+ }
82
+ }
83
+
84
+ return results
85
+ }
86
+
87
+ /**
88
+ * Extract DO class definitions from a TypeScript file
89
+ */
90
+ private async extractDOClasses(filePath: string): Promise<DOClassInfo[]> {
91
+ const content = fs.readFileSync(filePath, 'utf-8')
92
+ const classes: DOClassInfo[] = []
93
+
94
+ // Pattern to match DO class exports
95
+ // Matches: export class MyDO extends DurableObject
96
+ // Matches: export class MyDO implements DurableObject
97
+ const classPattern = /export\s+class\s+(\w+)(?:\s+extends\s+(\w+))?(?:\s+implements\s+[\w,\s]+)?\s*\{/g
98
+
99
+ let match: RegExpExecArray | null
100
+ while ((match = classPattern.exec(content)) !== null) {
101
+ const className = match[1]
102
+ const extendsClass = match[2]
103
+
104
+ // Check if it's a Durable Object
105
+ const isDO =
106
+ extendsClass === 'DurableObject' ||
107
+ extendsClass === 'DO' ||
108
+ content.includes(`DurableObjectState`) ||
109
+ content.includes(`DurableObject`) ||
110
+ className.endsWith('DO')
111
+
112
+ if (isDO) {
113
+ // Extract class body for method detection
114
+ const classBody = this.extractClassBody(content, match.index)
115
+
116
+ classes.push({
117
+ className,
118
+ filePath,
119
+ exports: [className],
120
+ hasAlarm: classBody.includes('alarm(') || classBody.includes('alarm ='),
121
+ hasFetch: classBody.includes('fetch(') || classBody.includes('fetch ='),
122
+ hasWebSocket: classBody.includes('webSocketMessage') || classBody.includes('WebSocket'),
123
+ })
124
+ }
125
+ }
126
+
127
+ return classes
128
+ }
129
+
130
+ /**
131
+ * Extract class body from content starting at given index
132
+ */
133
+ private extractClassBody(content: string, startIndex: number): string {
134
+ let braceCount = 0
135
+ let started = false
136
+ let body = ''
137
+
138
+ for (let i = startIndex; i < content.length; i++) {
139
+ const char = content[i]
140
+
141
+ if (char === '{') {
142
+ braceCount++
143
+ started = true
144
+ } else if (char === '}') {
145
+ braceCount--
146
+ }
147
+
148
+ if (started) {
149
+ body += char
150
+ if (braceCount === 0) {
151
+ break
152
+ }
153
+ }
154
+ }
155
+
156
+ return body
157
+ }
158
+
159
+ /**
160
+ * Get all registered DO classes
161
+ */
162
+ getClasses(): DOClassInfo[] {
163
+ return Array.from(this.classes.values())
164
+ }
165
+
166
+ /**
167
+ * Get a specific DO class by name
168
+ */
169
+ getClass(name: string): DOClassInfo | undefined {
170
+ return this.classes.get(name)
171
+ }
172
+
173
+ /**
174
+ * List all DO class names
175
+ */
176
+ listNames(): string[] {
177
+ return Array.from(this.classes.keys())
178
+ }
179
+
180
+ /**
181
+ * Clear the registry
182
+ */
183
+ clear(): void {
184
+ this.classes.clear()
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Create a new DO registry instance
190
+ */
191
+ export function createRegistry(options?: DORegistryOptions): DORegistry {
192
+ return new DORegistry(options)
193
+ }
@@ -0,0 +1,344 @@
1
+ /**
2
+ * Embedded DB
3
+ *
4
+ * SQLite-based storage for local DO development.
5
+ * Provides persistence for DO state, snapshots, and cloning.
6
+ */
7
+
8
+ import { Logger, createLogger } from '../utils/logger'
9
+ import * as fs from 'fs'
10
+ import * as path from 'path'
11
+ import * as os from 'os'
12
+
13
+ export interface DOState {
14
+ id: string
15
+ className: string
16
+ state: Record<string, unknown>
17
+ storage: Record<string, unknown>
18
+ createdAt: number
19
+ updatedAt: number
20
+ }
21
+
22
+ export interface DOSnapshot {
23
+ id: string
24
+ doId: string
25
+ state: DOState
26
+ createdAt: number
27
+ label?: string
28
+ }
29
+
30
+ export interface EmbeddedDBOptions {
31
+ logger?: Logger
32
+ persist?: boolean | string
33
+ }
34
+
35
+ /**
36
+ * Embedded SQLite database for DO storage
37
+ */
38
+ export class EmbeddedDB {
39
+ private logger: Logger
40
+ private dbPath: string
41
+ private db: unknown | null = null // Will be better-sqlite3 or bun:sqlite instance
42
+
43
+ constructor(options: EmbeddedDBOptions = {}) {
44
+ this.logger = options.logger ?? createLogger('db')
45
+
46
+ // Determine storage path
47
+ if (typeof options.persist === 'string') {
48
+ this.dbPath = options.persist
49
+ } else if (options.persist === false) {
50
+ this.dbPath = ':memory:'
51
+ } else {
52
+ // Default: .dotdo directory in project or home
53
+ const dotdoDir = this.findDotdoDir()
54
+ this.dbPath = path.join(dotdoDir, 'local.db')
55
+ }
56
+
57
+ this.ensureDir()
58
+ }
59
+
60
+ /**
61
+ * Find or create .dotdo directory
62
+ */
63
+ private findDotdoDir(): string {
64
+ // Look for project .dotdo first
65
+ const projectDir = process.cwd()
66
+ const projectDotdo = path.join(projectDir, '.dotdo')
67
+
68
+ if (fs.existsSync(projectDotdo)) {
69
+ return projectDotdo
70
+ }
71
+
72
+ // Fall back to home directory
73
+ const homeDotdo = path.join(os.homedir(), '.dotdo')
74
+ return homeDotdo
75
+ }
76
+
77
+ /**
78
+ * Ensure the database directory exists
79
+ */
80
+ private ensureDir(): void {
81
+ if (this.dbPath !== ':memory:') {
82
+ const dir = path.dirname(this.dbPath)
83
+ if (!fs.existsSync(dir)) {
84
+ fs.mkdirSync(dir, { recursive: true })
85
+ this.logger.debug(`Created directory: ${dir}`)
86
+ }
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Initialize the database with schema
92
+ */
93
+ async init(): Promise<void> {
94
+ // Use dynamic import for SQLite (works with both Bun and Node)
95
+ try {
96
+ // Bun has built-in SQLite
97
+ if (typeof Bun !== 'undefined') {
98
+ const { Database } = await import('bun:sqlite')
99
+ this.db = new Database(this.dbPath)
100
+ } else {
101
+ // Node.js fallback
102
+ const betterSqlite = await import('better-sqlite3')
103
+ this.db = new betterSqlite.default(this.dbPath)
104
+ }
105
+
106
+ this.logger.debug(`Database initialized at ${this.dbPath}`)
107
+ await this.createTables()
108
+ } catch (error) {
109
+ this.logger.error('Failed to initialize database', { error })
110
+ throw error
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Create database tables
116
+ */
117
+ private async createTables(): Promise<void> {
118
+ const db = this.getDB()
119
+
120
+ // Durable Object state table
121
+ db.exec(`
122
+ CREATE TABLE IF NOT EXISTS do_state (
123
+ id TEXT PRIMARY KEY,
124
+ class_name TEXT NOT NULL,
125
+ state TEXT NOT NULL DEFAULT '{}',
126
+ storage TEXT NOT NULL DEFAULT '{}',
127
+ created_at INTEGER NOT NULL DEFAULT (unixepoch()),
128
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch())
129
+ )
130
+ `)
131
+
132
+ // Snapshots table
133
+ db.exec(`
134
+ CREATE TABLE IF NOT EXISTS do_snapshots (
135
+ id TEXT PRIMARY KEY,
136
+ do_id TEXT NOT NULL,
137
+ state TEXT NOT NULL,
138
+ label TEXT,
139
+ created_at INTEGER NOT NULL DEFAULT (unixepoch()),
140
+ FOREIGN KEY (do_id) REFERENCES do_state(id)
141
+ )
142
+ `)
143
+
144
+ // Alarms table
145
+ db.exec(`
146
+ CREATE TABLE IF NOT EXISTS do_alarms (
147
+ id TEXT PRIMARY KEY,
148
+ do_id TEXT NOT NULL,
149
+ scheduled_at INTEGER NOT NULL,
150
+ created_at INTEGER NOT NULL DEFAULT (unixepoch()),
151
+ FOREIGN KEY (do_id) REFERENCES do_state(id)
152
+ )
153
+ `)
154
+
155
+ this.logger.debug('Database tables created')
156
+ }
157
+
158
+ /**
159
+ * Get the underlying database instance
160
+ */
161
+ private getDB(): { exec: (sql: string) => void; prepare: (sql: string) => { run: (...params: unknown[]) => void; get: (...params: unknown[]) => unknown; all: (...params: unknown[]) => unknown[] } } {
162
+ if (!this.db) {
163
+ throw new Error('Database not initialized. Call init() first.')
164
+ }
165
+ return this.db as { exec: (sql: string) => void; prepare: (sql: string) => { run: (...params: unknown[]) => void; get: (...params: unknown[]) => unknown; all: (...params: unknown[]) => unknown[] } }
166
+ }
167
+
168
+ /**
169
+ * Get database file path
170
+ */
171
+ getPath(): string {
172
+ return this.dbPath
173
+ }
174
+
175
+ /**
176
+ * List all DO instances
177
+ */
178
+ async list(className?: string): Promise<DOState[]> {
179
+ const db = this.getDB()
180
+
181
+ let rows: unknown[]
182
+ if (className) {
183
+ rows = db.prepare('SELECT * FROM do_state WHERE class_name = ?').all(className)
184
+ } else {
185
+ rows = db.prepare('SELECT * FROM do_state').all()
186
+ }
187
+
188
+ return (rows as Array<{ id: string; class_name: string; state: string; storage: string; created_at: number; updated_at: number }>).map(row => ({
189
+ id: row.id,
190
+ className: row.class_name,
191
+ state: JSON.parse(row.state),
192
+ storage: JSON.parse(row.storage),
193
+ createdAt: row.created_at,
194
+ updatedAt: row.updated_at,
195
+ }))
196
+ }
197
+
198
+ /**
199
+ * Get a specific DO instance
200
+ */
201
+ async get(id: string): Promise<DOState | null> {
202
+ const db = this.getDB()
203
+ const row = db.prepare('SELECT * FROM do_state WHERE id = ?').get(id) as { id: string; class_name: string; state: string; storage: string; created_at: number; updated_at: number } | undefined
204
+
205
+ if (!row) return null
206
+
207
+ return {
208
+ id: row.id,
209
+ className: row.class_name,
210
+ state: JSON.parse(row.state),
211
+ storage: JSON.parse(row.storage),
212
+ createdAt: row.created_at,
213
+ updatedAt: row.updated_at,
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Save a DO instance
219
+ */
220
+ async save(state: DOState): Promise<void> {
221
+ const db = this.getDB()
222
+ db.prepare(`
223
+ INSERT OR REPLACE INTO do_state (id, class_name, state, storage, created_at, updated_at)
224
+ VALUES (?, ?, ?, ?, ?, ?)
225
+ `).run(
226
+ state.id,
227
+ state.className,
228
+ JSON.stringify(state.state),
229
+ JSON.stringify(state.storage),
230
+ state.createdAt,
231
+ Date.now()
232
+ )
233
+ }
234
+
235
+ /**
236
+ * Delete a DO instance
237
+ */
238
+ async delete(id: string): Promise<boolean> {
239
+ const db = this.getDB()
240
+
241
+ // Delete associated snapshots first
242
+ db.prepare('DELETE FROM do_snapshots WHERE do_id = ?').run(id)
243
+ db.prepare('DELETE FROM do_alarms WHERE do_id = ?').run(id)
244
+ db.prepare('DELETE FROM do_state WHERE id = ?').run(id)
245
+
246
+ return true
247
+ }
248
+
249
+ /**
250
+ * Create a snapshot of a DO instance
251
+ */
252
+ async snapshot(doId: string, label?: string): Promise<string> {
253
+ const state = await this.get(doId)
254
+ if (!state) {
255
+ throw new Error(`DO not found: ${doId}`)
256
+ }
257
+
258
+ const snapshotId = `snap_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
259
+ const db = this.getDB()
260
+
261
+ db.prepare(`
262
+ INSERT INTO do_snapshots (id, do_id, state, label, created_at)
263
+ VALUES (?, ?, ?, ?, ?)
264
+ `).run(snapshotId, doId, JSON.stringify(state), label ?? null, Date.now())
265
+
266
+ return snapshotId
267
+ }
268
+
269
+ /**
270
+ * List snapshots for a DO
271
+ */
272
+ async listSnapshots(doId: string): Promise<DOSnapshot[]> {
273
+ const db = this.getDB()
274
+ const rows = db.prepare('SELECT * FROM do_snapshots WHERE do_id = ? ORDER BY created_at DESC').all(doId) as Array<{
275
+ id: string
276
+ do_id: string
277
+ state: string
278
+ label: string | null
279
+ created_at: number
280
+ }>
281
+
282
+ return rows.map(row => ({
283
+ id: row.id,
284
+ doId: row.do_id,
285
+ state: JSON.parse(row.state),
286
+ label: row.label ?? undefined,
287
+ createdAt: row.created_at,
288
+ }))
289
+ }
290
+
291
+ /**
292
+ * Restore a DO from a snapshot
293
+ */
294
+ async restore(doId: string, snapshotId: string): Promise<void> {
295
+ const db = this.getDB()
296
+ const row = db.prepare('SELECT * FROM do_snapshots WHERE id = ? AND do_id = ?').get(snapshotId, doId) as {
297
+ state: string
298
+ } | undefined
299
+
300
+ if (!row) {
301
+ throw new Error(`Snapshot not found: ${snapshotId}`)
302
+ }
303
+
304
+ const state: DOState = JSON.parse(row.state)
305
+ state.updatedAt = Date.now()
306
+ await this.save(state)
307
+ }
308
+
309
+ /**
310
+ * Clone a DO instance
311
+ */
312
+ async clone(sourceId: string, targetId: string): Promise<void> {
313
+ const state = await this.get(sourceId)
314
+ if (!state) {
315
+ throw new Error(`DO not found: ${sourceId}`)
316
+ }
317
+
318
+ const newState: DOState = {
319
+ ...state,
320
+ id: targetId,
321
+ createdAt: Date.now(),
322
+ updatedAt: Date.now(),
323
+ }
324
+
325
+ await this.save(newState)
326
+ }
327
+
328
+ /**
329
+ * Close the database connection
330
+ */
331
+ close(): void {
332
+ if (this.db && typeof (this.db as { close?: () => void }).close === 'function') {
333
+ (this.db as { close: () => void }).close()
334
+ this.db = null
335
+ }
336
+ }
337
+ }
338
+
339
+ /**
340
+ * Create a new embedded DB instance
341
+ */
342
+ export function createDB(options?: EmbeddedDBOptions): EmbeddedDB {
343
+ return new EmbeddedDB(options)
344
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Runtime Module
3
+ *
4
+ * Exports all runtime components for local DO development.
5
+ */
6
+
7
+ export { MiniflareAdapter, createAdapter, type MiniflareAdapterOptions, type RunningInstance } from './miniflare-adapter'
8
+ export { DORegistry, createRegistry, type DOClassInfo, type DORegistryOptions } from './do-registry'
9
+ export { EmbeddedDB, createDB, type DOState, type DOSnapshot, type EmbeddedDBOptions } from './embedded-db'