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,162 @@
1
+ /**
2
+ * Miniflare Adapter
3
+ *
4
+ * Wraps Miniflare for local DO runtime with full feature support.
5
+ * Provides DO isolation, SQLite storage, and RPC bridging.
6
+ */
7
+
8
+ import type { Miniflare, MiniflareOptions, DurableObjectNamespace } from 'miniflare'
9
+ import { Logger, createLogger } from '../utils/logger'
10
+ import { loadConfig, type DotdoConfig } from '../utils/config'
11
+ import { DORegistry } from './do-registry'
12
+ import { EmbeddedDB } from './embedded-db'
13
+
14
+ export interface MiniflareAdapterOptions {
15
+ port?: number
16
+ config?: DotdoConfig
17
+ logger?: Logger
18
+ modules?: boolean
19
+ persist?: boolean | string
20
+ durableObjects?: Record<string, { className: string; scriptName?: string }>
21
+ }
22
+
23
+ export interface RunningInstance {
24
+ miniflare: Miniflare
25
+ port: number
26
+ url: string
27
+ stop: () => Promise<void>
28
+ }
29
+
30
+ /**
31
+ * Creates and configures Miniflare for local DO development
32
+ */
33
+ export class MiniflareAdapter {
34
+ private miniflare: Miniflare | null = null
35
+ private logger: Logger
36
+ private config: DotdoConfig
37
+ private registry: DORegistry
38
+ private db: EmbeddedDB
39
+
40
+ constructor(options: MiniflareAdapterOptions = {}) {
41
+ this.logger = options.logger ?? createLogger('miniflare')
42
+ this.config = options.config ?? loadConfig()
43
+ this.registry = new DORegistry({ logger: this.logger })
44
+ this.db = new EmbeddedDB({ logger: this.logger, persist: options.persist })
45
+ }
46
+
47
+ /**
48
+ * Discover Durable Object classes from the project
49
+ */
50
+ async discoverDOs(): Promise<Record<string, { className: string }>> {
51
+ return this.registry.discover(this.config.srcDir ?? '.')
52
+ }
53
+
54
+ /**
55
+ * Build Miniflare options from config and discovered DOs
56
+ */
57
+ async buildOptions(overrides: Partial<MiniflareOptions> = {}): Promise<MiniflareOptions> {
58
+ const durableObjects = await this.discoverDOs()
59
+
60
+ const baseOptions: MiniflareOptions = {
61
+ modules: true,
62
+ script: this.config.entryPoint ?? 'index.ts',
63
+ port: this.config.port ?? 8787,
64
+
65
+ // Durable Object configuration
66
+ durableObjects,
67
+
68
+ // SQLite-backed DO storage
69
+ d1Databases: {
70
+ DB: this.db.getPath(),
71
+ },
72
+
73
+ // R2 for blob storage (local filesystem)
74
+ r2Buckets: ['BUCKET'],
75
+
76
+ // KV for simple key-value
77
+ kvNamespaces: ['KV'],
78
+
79
+ // Compatibility flags
80
+ compatibilityDate: this.config.compatibilityDate ?? '2024-01-01',
81
+ compatibilityFlags: this.config.compatibilityFlags ?? ['nodejs_compat'],
82
+
83
+ // Live reload on file changes
84
+ live: true,
85
+ }
86
+
87
+ return { ...baseOptions, ...overrides }
88
+ }
89
+
90
+ /**
91
+ * Start the Miniflare runtime
92
+ */
93
+ async start(options: Partial<MiniflareOptions> = {}): Promise<RunningInstance> {
94
+ if (this.miniflare) {
95
+ throw new Error('Miniflare already running')
96
+ }
97
+
98
+ // Dynamic import to avoid bundling issues
99
+ const { Miniflare } = await import('miniflare')
100
+
101
+ const mfOptions = await this.buildOptions(options)
102
+ this.logger.info('Starting Miniflare...', { port: mfOptions.port })
103
+
104
+ this.miniflare = new Miniflare(mfOptions)
105
+ await this.miniflare.ready
106
+
107
+ const port = mfOptions.port as number
108
+ const url = `http://localhost:${port}`
109
+
110
+ this.logger.success(`Miniflare running at ${url}`)
111
+
112
+ return {
113
+ miniflare: this.miniflare,
114
+ port,
115
+ url,
116
+ stop: () => this.stop(),
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Stop the Miniflare runtime
122
+ */
123
+ async stop(): Promise<void> {
124
+ if (this.miniflare) {
125
+ this.logger.info('Stopping Miniflare...')
126
+ await this.miniflare.dispose()
127
+ this.miniflare = null
128
+ this.logger.success('Miniflare stopped')
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Get a Durable Object namespace from the running instance
134
+ */
135
+ async getNamespace(name: string): Promise<DurableObjectNamespace | null> {
136
+ if (!this.miniflare) {
137
+ throw new Error('Miniflare not running')
138
+ }
139
+ return this.miniflare.getDurableObjectNamespace(name)
140
+ }
141
+
142
+ /**
143
+ * Get direct access to embedded DB for DO operations
144
+ */
145
+ getDB(): EmbeddedDB {
146
+ return this.db
147
+ }
148
+
149
+ /**
150
+ * Get the DO registry
151
+ */
152
+ getRegistry(): DORegistry {
153
+ return this.registry
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Create a new Miniflare adapter instance
159
+ */
160
+ export function createAdapter(options?: MiniflareAdapterOptions): MiniflareAdapter {
161
+ return new MiniflareAdapter(options)
162
+ }
package/cli/sandbox.ts ADDED
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Miniflare Code Sandbox (TDD Stub - Not Yet Implemented)
3
+ *
4
+ * This module provides code execution in an isolated Miniflare sandbox.
5
+ * Currently exports stubs for TDD RED phase testing.
6
+ *
7
+ * @see cli/tests/sandbox.test.ts for test specifications
8
+ */
9
+
10
+ // ============================================================================
11
+ // Type Definitions
12
+ // ============================================================================
13
+
14
+ export type FileType = 'js' | 'ts' | 'jsx' | 'tsx' | 'mdx' | 'md'
15
+
16
+ export interface SandboxConfig {
17
+ timeout?: number
18
+ memoryLimit?: number
19
+ }
20
+
21
+ export interface SandboxResult {
22
+ success: boolean
23
+ value?: unknown
24
+ error?: string
25
+ logs: Array<{
26
+ level: 'log' | 'error' | 'warn' | 'info' | 'debug'
27
+ args: unknown[]
28
+ }>
29
+ executionTime?: number
30
+ }
31
+
32
+ export interface Sandbox {
33
+ run(code: string, fileType?: FileType): Promise<SandboxResult>
34
+ dispose(): Promise<void>
35
+ }
36
+
37
+ // ============================================================================
38
+ // Stub Implementations (RED Phase - Not Yet Implemented)
39
+ // ============================================================================
40
+
41
+ /**
42
+ * Execute code in a Miniflare sandbox
43
+ * @stub Not yet implemented - will fail tests
44
+ */
45
+ export async function runInSandbox(
46
+ _code: string,
47
+ _fileType: FileType = 'ts',
48
+ _config?: SandboxConfig
49
+ ): Promise<SandboxResult> {
50
+ // Stub implementation - returns failure for all tests
51
+ throw new Error('runInSandbox not implemented yet - TDD RED phase')
52
+ }
53
+
54
+ /**
55
+ * Create a reusable sandbox instance
56
+ * @stub Not yet implemented - will fail tests
57
+ */
58
+ export async function createSandbox(_config?: SandboxConfig): Promise<Sandbox> {
59
+ // Stub implementation - returns failure for all tests
60
+ throw new Error('createSandbox not implemented yet - TDD RED phase')
61
+ }
62
+
63
+ /**
64
+ * Transform code from TypeScript/JSX/TSX to JavaScript
65
+ * @stub Not yet implemented - will fail tests
66
+ */
67
+ export async function transformCode(
68
+ _code: string,
69
+ _fileType: FileType
70
+ ): Promise<string> {
71
+ // Stub implementation - returns failure for all tests
72
+ throw new Error('transformCode not implemented yet - TDD RED phase')
73
+ }
74
+
75
+ /**
76
+ * Detect file type from file path
77
+ * @stub Not yet implemented - will fail tests
78
+ */
79
+ export function detectFileType(_filePath: string): FileType {
80
+ // Stub implementation - returns failure for all tests
81
+ throw new Error('detectFileType not implemented yet - TDD RED phase')
82
+ }
@@ -0,0 +1,174 @@
1
+ /**
2
+ * CLI Argument Parsing
3
+ *
4
+ * Simple argument parser for CLI commands.
5
+ */
6
+
7
+ // ============================================================================
8
+ // Types
9
+ // ============================================================================
10
+
11
+ export interface ParsedArgs {
12
+ /** Positional arguments */
13
+ positional: string[]
14
+ /** Flag arguments (--flag or --flag=value) */
15
+ flags: Record<string, string | boolean>
16
+ }
17
+
18
+ // ============================================================================
19
+ // Parsing
20
+ // ============================================================================
21
+
22
+ /**
23
+ * Parse command arguments into positional and flag arguments
24
+ */
25
+ export function parseArgs(args: string[]): ParsedArgs {
26
+ const positional: string[] = []
27
+ const flags: Record<string, string | boolean> = {}
28
+
29
+ let i = 0
30
+ while (i < args.length) {
31
+ const arg = args[i]
32
+
33
+ if (arg.startsWith('--')) {
34
+ const rest = arg.slice(2)
35
+
36
+ // Handle --flag=value
37
+ if (rest.includes('=')) {
38
+ const [key, ...valueParts] = rest.split('=')
39
+ flags[key] = valueParts.join('=')
40
+ }
41
+ // Handle --no-flag (boolean negation)
42
+ else if (rest.startsWith('no-')) {
43
+ flags[rest.slice(3)] = false
44
+ }
45
+ // Handle --flag value or --flag (boolean)
46
+ else {
47
+ const nextArg = args[i + 1]
48
+ if (nextArg && !nextArg.startsWith('-')) {
49
+ flags[rest] = nextArg
50
+ i++
51
+ } else {
52
+ flags[rest] = true
53
+ }
54
+ }
55
+ }
56
+ // Handle -f value
57
+ else if (arg.startsWith('-') && arg.length === 2) {
58
+ const key = arg.slice(1)
59
+ const nextArg = args[i + 1]
60
+ if (nextArg && !nextArg.startsWith('-')) {
61
+ flags[key] = nextArg
62
+ i++
63
+ } else {
64
+ flags[key] = true
65
+ }
66
+ }
67
+ // Positional argument
68
+ else {
69
+ positional.push(arg)
70
+ }
71
+
72
+ i++
73
+ }
74
+
75
+ return { positional, flags }
76
+ }
77
+
78
+ /**
79
+ * Get a required positional argument or throw
80
+ */
81
+ export function requirePositional(
82
+ args: ParsedArgs,
83
+ index: number,
84
+ name: string
85
+ ): string {
86
+ const value = args.positional[index]
87
+ if (!value) {
88
+ throw new Error(`Missing required argument: ${name}`)
89
+ }
90
+ return value
91
+ }
92
+
93
+ /**
94
+ * Get a required flag value or throw
95
+ */
96
+ export function requireFlag(
97
+ args: ParsedArgs,
98
+ name: string,
99
+ description?: string
100
+ ): string {
101
+ const value = args.flags[name]
102
+ if (value === undefined || typeof value !== 'string') {
103
+ throw new Error(`Missing required flag: --${name}${description ? ` (${description})` : ''}`)
104
+ }
105
+ return value
106
+ }
107
+
108
+ /**
109
+ * Get a flag value as string (or undefined)
110
+ */
111
+ export function getStringFlag(args: ParsedArgs, name: string): string | undefined {
112
+ const value = args.flags[name]
113
+ if (typeof value === 'string') {
114
+ return value
115
+ }
116
+ // Handle case where flag exists but has no value
117
+ if (value === true) {
118
+ return undefined
119
+ }
120
+ return undefined
121
+ }
122
+
123
+ /**
124
+ * Get a flag value as boolean
125
+ */
126
+ export function getBooleanFlag(args: ParsedArgs, name: string, defaultValue = false): boolean {
127
+ const value = args.flags[name]
128
+ if (value === undefined) {
129
+ return defaultValue
130
+ }
131
+ if (typeof value === 'boolean') {
132
+ return value
133
+ }
134
+ return value.toLowerCase() === 'true'
135
+ }
136
+
137
+ /**
138
+ * Get a flag value as number (or undefined)
139
+ */
140
+ export function getNumberFlag(args: ParsedArgs, name: string): number | undefined {
141
+ const value = args.flags[name]
142
+ if (typeof value === 'string') {
143
+ const num = Number(value)
144
+ if (!isNaN(num)) {
145
+ return num
146
+ }
147
+ }
148
+ return undefined
149
+ }
150
+
151
+ // ============================================================================
152
+ // Validation
153
+ // ============================================================================
154
+
155
+ /**
156
+ * Validate phone number format (E.164)
157
+ */
158
+ export function isValidPhoneNumber(phone: string): boolean {
159
+ return /^\+[1-9]\d{1,14}$/.test(phone)
160
+ }
161
+
162
+ /**
163
+ * Validate email address format
164
+ */
165
+ export function isValidEmail(email: string): boolean {
166
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
167
+ }
168
+
169
+ /**
170
+ * Validate positive integer
171
+ */
172
+ export function isPositiveInteger(value: number): boolean {
173
+ return Number.isInteger(value) && value > 0
174
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * CLI Authentication
3
+ *
4
+ * Handles authentication for CLI service commands.
5
+ * Uses tokens stored by device-auth.ts (via oauth.do)
6
+ */
7
+
8
+ import { getStoredToken } from '../device-auth'
9
+
10
+ export class AuthError extends Error {
11
+ constructor(message: string) {
12
+ super(message)
13
+ this.name = 'AuthError'
14
+ }
15
+ }
16
+
17
+ /**
18
+ * Get the current access token or throw if not logged in
19
+ */
20
+ export async function getAccessToken(): Promise<string> {
21
+ const token = await getStoredToken()
22
+
23
+ if (!token) {
24
+ throw new AuthError('Not logged in. Run `do login` first.')
25
+ }
26
+
27
+ // Check if token is expired (without refresh token)
28
+ if (token.expires_at && token.expires_at < Date.now() && !token.refresh_token) {
29
+ throw new AuthError('Session expired. Run `do login` to re-authenticate.')
30
+ }
31
+
32
+ return token.access_token
33
+ }
34
+
35
+ /**
36
+ * Get authorization headers for API requests
37
+ */
38
+ export async function getAuthHeaders(): Promise<Record<string, string>> {
39
+ const token = await getAccessToken()
40
+ return {
41
+ Authorization: `Bearer ${token}`,
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Check if user is logged in (without throwing)
47
+ */
48
+ export async function isLoggedIn(): Promise<boolean> {
49
+ try {
50
+ await getAccessToken()
51
+ return true
52
+ } catch {
53
+ return false
54
+ }
55
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Call Command
3
+ *
4
+ * Make voice calls via calls.do
5
+ *
6
+ * Usage:
7
+ * do call +15551234567 "Your appointment is tomorrow"
8
+ * do call +15551234567 "Hello" --from +15559876543
9
+ * do call +15551234567 "Hello" --voice alice
10
+ * do call +15551234567 "Hello" --json
11
+ */
12
+
13
+ import { parseArgs, requirePositional, getStringFlag, getBooleanFlag, isValidPhoneNumber } from '../args'
14
+ import { callsRequest } from '../rpc'
15
+ import { formatJson } from '../output'
16
+ import { getConfig } from '../config'
17
+
18
+ // ============================================================================
19
+ // Types
20
+ // ============================================================================
21
+
22
+ interface CallRequest {
23
+ to: string
24
+ message: string
25
+ from?: string
26
+ voice?: string
27
+ }
28
+
29
+ interface CallResponse {
30
+ call_id: string
31
+ status: string
32
+ }
33
+
34
+ // ============================================================================
35
+ // Command
36
+ // ============================================================================
37
+
38
+ export async function run(rawArgs: string[]): Promise<void> {
39
+ const args = parseArgs(rawArgs)
40
+
41
+ // Validate required arguments
42
+ const to = requirePositional(args, 0, 'phone number')
43
+ const message = requirePositional(args, 1, 'message')
44
+
45
+ if (!isValidPhoneNumber(to)) {
46
+ throw new Error(`Invalid phone number format. Use E.164 format (e.g., +15551234567)`)
47
+ }
48
+
49
+ // Build request
50
+ const request: CallRequest = {
51
+ to,
52
+ message,
53
+ }
54
+
55
+ const from = getStringFlag(args, 'from')
56
+ if (from) {
57
+ if (!isValidPhoneNumber(from)) {
58
+ throw new Error(`Invalid --from phone number format. Use E.164 format (e.g., +15551234567)`)
59
+ }
60
+ request.from = from
61
+ }
62
+
63
+ const voice = getStringFlag(args, 'voice')
64
+ if (voice) {
65
+ request.voice = voice
66
+ }
67
+
68
+ // Make request
69
+ const response = await callsRequest<CallResponse>('/calls', {
70
+ method: 'POST',
71
+ body: request,
72
+ })
73
+
74
+ // Output result
75
+ const config = await getConfig()
76
+ const jsonOutput = getBooleanFlag(args, 'json') || config.json_output
77
+
78
+ if (jsonOutput) {
79
+ console.log(formatJson(response))
80
+ } else {
81
+ console.log(`Call initiated: ${response.call_id}`)
82
+ console.log(`Status: ${response.status}`)
83
+ }
84
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Charge Command
3
+ *
4
+ * Create charges via payments.do
5
+ *
6
+ * Usage:
7
+ * do charge cus_123 --amount 9900
8
+ * do charge cus_123 --amount 1000 --currency eur
9
+ * do charge cus_123 --amount 5000 --description "Monthly subscription"
10
+ * do charge cus_123 --amount 1000 --metadata '{"order_id":"ord_123"}'
11
+ * do charge cus_123 --amount 1000 --json
12
+ */
13
+
14
+ import { parseArgs, requirePositional, requireFlag, getStringFlag, getBooleanFlag, getNumberFlag, isPositiveInteger } from '../args'
15
+ import { paymentsRequest } from '../rpc'
16
+ import { formatJson } from '../output'
17
+ import { getConfig } from '../config'
18
+
19
+ // ============================================================================
20
+ // Types
21
+ // ============================================================================
22
+
23
+ interface ChargeRequest {
24
+ customer: string
25
+ amount: number
26
+ currency: string
27
+ description?: string
28
+ metadata?: Record<string, unknown>
29
+ }
30
+
31
+ interface ChargeResponse {
32
+ charge_id: string
33
+ status: string
34
+ amount: number
35
+ currency: string
36
+ }
37
+
38
+ // ============================================================================
39
+ // Command
40
+ // ============================================================================
41
+
42
+ export async function run(rawArgs: string[]): Promise<void> {
43
+ const args = parseArgs(rawArgs)
44
+
45
+ // Validate required arguments
46
+ const customer = requirePositional(args, 0, 'customer ID')
47
+ const amountStr = requireFlag(args, 'amount', 'amount in smallest currency unit (e.g., cents)')
48
+ const amount = parseInt(amountStr, 10)
49
+
50
+ if (isNaN(amount) || !isPositiveInteger(amount)) {
51
+ throw new Error(`Invalid --amount: must be a positive integer (in smallest currency unit)`)
52
+ }
53
+
54
+ // Build request
55
+ const config = await getConfig()
56
+ const request: ChargeRequest = {
57
+ customer,
58
+ amount,
59
+ currency: getStringFlag(args, 'currency') ?? config.default_currency ?? 'usd',
60
+ }
61
+
62
+ const description = getStringFlag(args, 'description')
63
+ if (description) {
64
+ request.description = description
65
+ }
66
+
67
+ const metadata = getStringFlag(args, 'metadata')
68
+ if (metadata) {
69
+ try {
70
+ request.metadata = JSON.parse(metadata)
71
+ } catch {
72
+ throw new Error(`Invalid --metadata: expected valid JSON`)
73
+ }
74
+ }
75
+
76
+ // Make request
77
+ const response = await paymentsRequest<ChargeResponse>('/charges', {
78
+ method: 'POST',
79
+ body: request,
80
+ })
81
+
82
+ // Output result
83
+ const jsonOutput = getBooleanFlag(args, 'json') || config.json_output
84
+
85
+ if (jsonOutput) {
86
+ console.log(formatJson(response))
87
+ } else {
88
+ console.log(`Charge created: ${response.charge_id}`)
89
+ if (response.amount !== undefined && response.currency) {
90
+ console.log(`Amount: ${(response.amount / 100).toFixed(2)} ${response.currency.toUpperCase()}`)
91
+ }
92
+ if (response.status) {
93
+ console.log(`Status: ${response.status}`)
94
+ }
95
+ }
96
+ }