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
|
@@ -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
|
+
}
|
package/cli/src/args.ts
ADDED
|
@@ -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
|
+
}
|
package/cli/src/auth.ts
ADDED
|
@@ -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
|
+
}
|