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.
- package/cli/README.md +238 -0
- package/cli/agent.ts +72 -0
- package/cli/bin.js +44 -0
- package/cli/bin.ts +38 -0
- package/cli/build.ts +157 -0
- package/cli/commands/auth/login.ts +14 -0
- package/cli/commands/auth/logout.ts +6 -0
- package/cli/commands/auth/whoami.ts +16 -0
- package/cli/commands/deploy-multi.ts +245 -0
- package/cli/commands/dev/deploy.ts +100 -0
- package/cli/commands/dev/dev.ts +95 -0
- package/cli/commands/dev/logs.ts +91 -0
- package/cli/commands/dev-local.ts +88 -0
- package/cli/commands/do-ops.ts +314 -0
- package/cli/commands/index.ts +100 -0
- package/cli/commands/init.ts +247 -0
- package/cli/commands/introspect/emitter.ts +315 -0
- package/cli/commands/introspect/index.ts +193 -0
- package/cli/commands/link.ts +598 -0
- package/cli/commands/snippets.ts +415 -0
- package/cli/commands/tunnel.ts +239 -0
- package/cli/device-auth.ts +289 -0
- package/cli/fallback.ts +12 -0
- package/cli/index.ts +121 -0
- package/cli/main.ts +246 -0
- package/cli/mcp-stdio.ts +790 -0
- package/cli/package.json +62 -0
- package/cli/runtime/do-registry.ts +193 -0
- package/cli/runtime/embedded-db.ts +344 -0
- package/cli/runtime/index.ts +9 -0
- package/cli/runtime/miniflare-adapter.ts +162 -0
- package/cli/sandbox.ts +82 -0
- package/cli/src/args.ts +174 -0
- package/cli/src/auth.ts +55 -0
- package/cli/src/commands/call.ts +84 -0
- package/cli/src/commands/charge.ts +96 -0
- package/cli/src/commands/config.ts +115 -0
- package/cli/src/commands/email.ts +112 -0
- package/cli/src/commands/llm.ts +115 -0
- package/cli/src/commands/queue.ts +134 -0
- package/cli/src/commands/text.ts +86 -0
- package/cli/src/config.ts +185 -0
- package/cli/src/output.ts +246 -0
- package/cli/src/rpc.ts +192 -0
- package/cli/utils/config.ts +282 -0
- package/cli/utils/detect.ts +73 -0
- package/cli/utils/index.ts +15 -0
- package/cli/utils/logger.ts +232 -0
- package/dist/ai/template-literals.js +2 -2
- package/dist/ai/template-literals.js.map +1 -1
- package/dist/api/middleware/auth.js +3 -2
- package/dist/api/middleware/auth.js.map +1 -1
- package/dist/db/iceberg/inverted-index.js +1 -1
- package/dist/db/iceberg/inverted-index.js.map +1 -1
- package/dist/db/iceberg/puffin.js.map +1 -1
- package/dist/db/json-indexes.js.map +1 -1
- package/dist/db/objects.js.map +1 -1
- package/dist/db/primitives/dag-scheduler/index.js +1 -1
- package/dist/db/primitives/dag-scheduler/index.js.map +1 -1
- package/dist/db/primitives/observability.js.map +1 -1
- package/dist/db/primitives/schema-evolution.js.map +1 -1
- package/dist/db/primitives/temporal-store.js.map +1 -1
- package/dist/db/primitives/typed-column-store.js.map +1 -1
- package/dist/db/primitives/utils/duration.js.map +1 -1
- package/dist/db/primitives/utils/murmur3.js +12 -14
- package/dist/db/primitives/utils/murmur3.js.map +1 -1
- package/dist/db/primitives/window-manager.js.map +1 -1
- package/dist/db/stores.js.map +1 -1
- package/dist/db/things.js.map +1 -1
- package/dist/lib/DODispatcher.js +2 -2
- package/dist/lib/DODispatcher.js.map +1 -1
- package/dist/lib/auto-wiring.js.map +1 -1
- package/dist/lib/channels/email.js +1 -1
- package/dist/lib/channels/email.js.map +1 -1
- package/dist/lib/channels/slack-blockkit.js.map +1 -1
- package/dist/lib/cloudflare/ai.js +1 -1
- package/dist/lib/cloudflare/ai.js.map +1 -1
- package/dist/lib/cloudflare/kv.js +1 -1
- package/dist/lib/cloudflare/kv.js.map +1 -1
- package/dist/lib/cloudflare/r2.js +3 -3
- package/dist/lib/cloudflare/r2.js.map +1 -1
- package/dist/lib/cloudflare/vectorize.js.map +1 -1
- package/dist/lib/cloudflare/workflows.js.map +1 -1
- package/dist/lib/executors/AgenticFunctionExecutor.js.map +1 -1
- package/dist/lib/executors/CodeFunctionExecutor.js.map +1 -1
- package/dist/lib/executors/GenerativeFunctionExecutor.js.map +1 -1
- package/dist/lib/executors/HumanFunctionExecutor.js +1 -1
- package/dist/lib/executors/HumanFunctionExecutor.js.map +1 -1
- package/dist/lib/executors/ParallelStepExecutor.js.map +1 -1
- package/dist/lib/experiments.js.map +1 -1
- package/dist/lib/flags/store.js.map +1 -1
- package/dist/lib/functions/FunctionComposition.js.map +1 -1
- package/dist/lib/functions/FunctionMiddleware.js.map +1 -1
- package/dist/lib/functions/FunctionRegistry.js.map +1 -1
- package/dist/lib/humans/templates.js.map +1 -1
- package/dist/lib/identity.js +2 -2
- package/dist/lib/identity.js.map +1 -1
- package/dist/lib/logging/index.js.map +1 -1
- package/dist/lib/mixins/bash.js +1 -73
- package/dist/lib/mixins/bash.js.map +1 -1
- package/dist/lib/mixins/git.js +0 -5
- package/dist/lib/mixins/git.js.map +1 -1
- package/dist/lib/mixins/npm.js.map +1 -1
- package/dist/lib/noun-id.js.map +1 -1
- package/dist/lib/rate-limit/sliding-window.js.map +1 -1
- package/dist/lib/rpc/bindings.js.map +1 -1
- package/dist/lib/safe-stringify.js.map +1 -1
- package/dist/lib/sandbox/miniflare-sandbox.js.map +1 -1
- package/dist/lib/sqids.js.map +1 -1
- package/dist/lib/sql/adapters/node-sql-parser.js.map +1 -1
- package/dist/lib/sql/adapters/pgsql-parser.js +19 -18
- package/dist/lib/sql/adapters/pgsql-parser.js.map +1 -1
- package/dist/metrics/hunch.js.map +1 -1
- package/dist/objects/API.js +1 -1
- package/dist/objects/API.js.map +1 -1
- package/dist/objects/Agent.js.map +1 -1
- package/dist/objects/Browser.js.map +1 -1
- package/dist/objects/CLI.js.map +1 -1
- package/dist/objects/DOBase.js.map +1 -1
- package/dist/objects/DOCache.js +153 -0
- package/dist/objects/DOCache.js.map +1 -0
- package/dist/objects/DOFull.js.map +1 -1
- package/dist/objects/Entity.js.map +1 -1
- package/dist/objects/Human.js.map +1 -1
- package/dist/objects/IcebergMetadataDO.js.map +1 -1
- package/dist/objects/IntegrationsDO.js.map +1 -1
- package/dist/objects/ObservabilityBroadcaster.js.map +1 -1
- package/dist/objects/Package.js.map +1 -1
- package/dist/objects/Product.js +1 -1
- package/dist/objects/Product.js.map +1 -1
- package/dist/objects/SaaS.js.map +1 -1
- package/dist/objects/SandboxDO.js.map +1 -1
- package/dist/objects/Service.js.map +1 -1
- package/dist/objects/VectorShardDO.js +9 -7
- package/dist/objects/VectorShardDO.js.map +1 -1
- package/dist/objects/Workflow.js.map +1 -1
- package/dist/objects/WorkflowFactory.js.map +1 -1
- package/dist/objects/WorkflowRuntime.js.map +1 -1
- package/dist/objects/lifecycle/Branch.js.map +1 -1
- package/dist/objects/lifecycle/Clone.js +1 -1
- package/dist/objects/lifecycle/Clone.js.map +1 -1
- package/dist/objects/lifecycle/Compact.js.map +1 -1
- package/dist/objects/lifecycle/Shard.js.map +1 -1
- package/dist/objects/persistence/checkpoint-manager.js.map +1 -1
- package/dist/objects/persistence/migration-runner.js.map +1 -1
- package/dist/objects/persistence/replication-manager.js +2 -2
- package/dist/objects/persistence/replication-manager.js.map +1 -1
- package/dist/objects/persistence/tiered-storage-manager.js.map +1 -1
- package/dist/objects/persistence/wal-manager.js.map +1 -1
- package/dist/objects/transport/auth-layer.js.map +1 -1
- package/dist/objects/transport/chain.js.map +1 -1
- package/dist/objects/transport/mcp-server.js +7 -6
- package/dist/objects/transport/mcp-server.js.map +1 -1
- package/dist/objects/transport/rest-autowire.js +3 -2
- package/dist/objects/transport/rest-autowire.js.map +1 -1
- package/dist/objects/transport/rest-router.js.map +1 -1
- package/dist/objects/transport/rpc-server.js +18 -15
- package/dist/objects/transport/rpc-server.js.map +1 -1
- package/dist/objects/transport/shared.js +2 -1
- package/dist/objects/transport/shared.js.map +1 -1
- package/dist/snippets/artifacts-ingest.js.map +1 -1
- package/dist/snippets/artifacts-serve.js.map +1 -1
- package/dist/snippets/search.js.map +1 -1
- package/dist/workflows/ScheduleManager.js.map +1 -1
- package/dist/workflows/StepResultStorage.js.map +1 -1
- package/dist/workflows/WaitForEventManager.js.map +1 -1
- package/dist/workflows/compat/backends/cloudflare-workflows.js.map +1 -1
- package/dist/workflows/compat/inngest/index.js.map +1 -1
- package/dist/workflows/compat/qstash/index.js.map +1 -1
- package/dist/workflows/compat/temporal/client.js.map +1 -1
- package/dist/workflows/compat/temporal/index.js.map +1 -1
- package/dist/workflows/compat/trigger/index.js.map +1 -1
- package/dist/workflows/compat/utils/index.js.map +1 -1
- package/dist/workflows/context/correlation.js +2 -2
- package/dist/workflows/context/correlation.js.map +1 -1
- package/dist/workflows/context/experiment.js +1 -1
- package/dist/workflows/context/experiment.js.map +1 -1
- package/dist/workflows/context/flag.js +1 -1
- package/dist/workflows/context/flag.js.map +1 -1
- package/dist/workflows/context/measure.js +1 -1
- package/dist/workflows/context/measure.js.map +1 -1
- package/dist/workflows/context/rate-limit.js.map +1 -1
- package/dist/workflows/data/entity-events/entity-events.js.map +1 -1
- package/dist/workflows/data/experiment/index.js.map +1 -1
- package/dist/workflows/data/goal/context.js +1 -1
- package/dist/workflows/data/goal/context.js.map +1 -1
- package/dist/workflows/data/measure/index.js +1 -1
- package/dist/workflows/data/measure/index.js.map +1 -1
- package/dist/workflows/data/stream/index.js +10 -76
- package/dist/workflows/data/stream/index.js.map +1 -1
- package/dist/workflows/data/track/context.js.map +1 -1
- package/dist/workflows/data/view/context.js.map +1 -1
- package/dist/workflows/domain.js.map +1 -1
- package/dist/workflows/flags.js +1 -1
- package/dist/workflows/flags.js.map +1 -1
- package/dist/workflows/hash.js.map +1 -1
- package/dist/workflows/on.js +1 -1
- package/dist/workflows/on.js.map +1 -1
- package/dist/workflows/schedule-builder.js.map +1 -1
- package/dist/workflows/visibility/index.js +0 -2
- package/dist/workflows/visibility/index.js.map +1 -1
- package/dist/workflows/visibility/query-parser.js.map +1 -1
- package/package.json +18 -3
- package/dist/api/analytics/router.js +0 -601
- package/dist/api/analytics/router.js.map +0 -1
- package/dist/api/index.js +0 -158
- package/dist/api/index.js.map +0 -1
- package/dist/api/middleware/error-handling.js +0 -176
- package/dist/api/middleware/error-handling.js.map +0 -1
- package/dist/api/middleware/request-id.js +0 -21
- package/dist/api/middleware/request-id.js.map +0 -1
- package/dist/api/pages.js +0 -1180
- package/dist/api/pages.js.map +0 -1
- package/dist/api/routes/api.js +0 -612
- package/dist/api/routes/api.js.map +0 -1
- package/dist/api/routes/browsers.js +0 -471
- package/dist/api/routes/browsers.js.map +0 -1
- package/dist/api/routes/do.js +0 -188
- package/dist/api/routes/do.js.map +0 -1
- package/dist/api/routes/mcp.js +0 -459
- package/dist/api/routes/mcp.js.map +0 -1
- package/dist/api/routes/obs.js +0 -445
- package/dist/api/routes/obs.js.map +0 -1
- package/dist/api/routes/openapi.js +0 -794
- package/dist/api/routes/openapi.js.map +0 -1
- package/dist/api/routes/rpc.js +0 -1103
- package/dist/api/routes/rpc.js.map +0 -1
- package/dist/api/routes/sandboxes.js +0 -389
- package/dist/api/routes/sandboxes.js.map +0 -1
- package/dist/api/test-do.js +0 -38
- package/dist/api/test-do.js.map +0 -1
- package/dist/api/types.js +0 -11
- package/dist/api/types.js.map +0 -1
- package/dist/cli/bin.js +0 -2
- package/dist/cli/main.js +0 -52342
- package/dist/do/bash.js +0 -35
- package/dist/do/bash.js.map +0 -1
- package/dist/do/fs.js +0 -25
- package/dist/do/fs.js.map +0 -1
- package/dist/do/full.js +0 -61
- package/dist/do/full.js.map +0 -1
- package/dist/do/git.js +0 -28
- package/dist/do/git.js.map +0 -1
- package/dist/do/index.js +0 -52
- package/dist/do/index.js.map +0 -1
- package/dist/lib/agent/tools/bash.js +0 -336
- package/dist/lib/agent/tools/bash.js.map +0 -1
- package/dist/lib/agent/tools/edit.js +0 -157
- package/dist/lib/agent/tools/edit.js.map +0 -1
- package/dist/lib/agent/tools/glob.js +0 -137
- package/dist/lib/agent/tools/glob.js.map +0 -1
- package/dist/lib/agent/tools/grep.js +0 -315
- package/dist/lib/agent/tools/grep.js.map +0 -1
- package/dist/lib/agent/tools/index.js +0 -71
- package/dist/lib/agent/tools/index.js.map +0 -1
- package/dist/lib/agent/tools/read.js +0 -212
- package/dist/lib/agent/tools/read.js.map +0 -1
- package/dist/lib/agent/tools/types.js +0 -197
- package/dist/lib/agent/tools/types.js.map +0 -1
- package/dist/lib/agent/tools/write.js +0 -159
- package/dist/lib/agent/tools/write.js.map +0 -1
- package/dist/lib/mixins/index.js +0 -29
- package/dist/lib/mixins/index.js.map +0 -1
- package/dist/primitives/bashx/src/ast/analyze.js +0 -1472
- package/dist/primitives/bashx/src/ast/analyze.js.map +0 -1
- package/dist/primitives/bashx/src/ast/parser.js +0 -1488
- package/dist/primitives/bashx/src/ast/parser.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/crypto.js +0 -1954
- package/dist/primitives/bashx/src/do/commands/crypto.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/data-processing.js +0 -1812
- package/dist/primitives/bashx/src/do/commands/data-processing.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/extended-utils.js +0 -804
- package/dist/primitives/bashx/src/do/commands/extended-utils.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/math-control.js +0 -1122
- package/dist/primitives/bashx/src/do/commands/math-control.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/posix-utils.js +0 -1015
- package/dist/primitives/bashx/src/do/commands/posix-utils.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/system-utils.js +0 -687
- package/dist/primitives/bashx/src/do/commands/system-utils.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/test-command.js +0 -523
- package/dist/primitives/bashx/src/do/commands/test-command.js.map +0 -1
- package/dist/primitives/bashx/src/do/commands/text-processing.js +0 -1550
- package/dist/primitives/bashx/src/do/commands/text-processing.js.map +0 -1
- package/dist/primitives/bashx/src/do/container-executor.js +0 -429
- package/dist/primitives/bashx/src/do/container-executor.js.map +0 -1
- package/dist/primitives/bashx/src/do/index.js +0 -668
- package/dist/primitives/bashx/src/do/index.js.map +0 -1
- package/dist/primitives/bashx/src/do/tiered-executor.js +0 -2647
- package/dist/primitives/bashx/src/do/tiered-executor.js.map +0 -1
- package/dist/primitives/bashx/src/do/worker.js +0 -352
- package/dist/primitives/bashx/src/do/worker.js.map +0 -1
- package/dist/primitives/bashx/src/types.js +0 -10
- package/dist/primitives/bashx/src/types.js.map +0 -1
- package/dist/primitives/fsx/core/backend.js +0 -480
- package/dist/primitives/fsx/core/backend.js.map +0 -1
- package/dist/primitives/fsx/core/constants.js +0 -140
- package/dist/primitives/fsx/core/constants.js.map +0 -1
- package/dist/primitives/fsx/core/fsx.js +0 -1184
- package/dist/primitives/fsx/core/fsx.js.map +0 -1
- package/dist/primitives/fsx/core/glob/glob.js +0 -438
- package/dist/primitives/fsx/core/glob/glob.js.map +0 -1
- package/dist/primitives/fsx/core/glob/index.js +0 -8
- package/dist/primitives/fsx/core/glob/index.js.map +0 -1
- package/dist/primitives/fsx/core/glob/match.js +0 -392
- package/dist/primitives/fsx/core/glob/match.js.map +0 -1
- package/dist/primitives/fsx/core/types.js +0 -307
- package/dist/primitives/fsx/core/types.js.map +0 -1
- package/dist/sdk/capnweb-compat.js +0 -42
- package/dist/sdk/capnweb-compat.js.map +0 -1
- package/dist/sdk/client.js +0 -20
- package/dist/sdk/client.js.map +0 -1
- package/dist/sdk/index.js +0 -17
- package/dist/sdk/index.js.map +0 -1
package/cli/package.json
ADDED
|
@@ -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'
|