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
@@ -1 +0,0 @@
1
- {"version":3,"file":"pages.js","sourceRoot":"","sources":["../../api/pages.ts"],"names":[],"mappings":"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"}
@@ -1,612 +0,0 @@
1
- import { Hono } from 'hono';
2
- /**
3
- * Get the ThingsDO stub for storage operations.
4
- * All API instances use the same DO instance named 'things'.
5
- */
6
- function getThingsStub(env) {
7
- const id = env.DO.idFromName('things');
8
- return env.DO.get(id);
9
- }
10
- export const apiRoutes = new Hono();
11
- // API info - root endpoint (handles both / and empty path)
12
- apiRoutes.get('/', (c) => {
13
- return c.json({
14
- name: 'dotdo',
15
- version: '0.0.1',
16
- endpoints: ['/api/health', '/api/things'],
17
- });
18
- });
19
- // Also handle empty path for /api (mounted route without trailing slash)
20
- apiRoutes.get('', (c) => {
21
- return c.json({
22
- name: 'dotdo',
23
- version: '0.0.1',
24
- endpoints: ['/api/health', '/api/things'],
25
- });
26
- });
27
- // Health check - simple response (only GET allowed)
28
- apiRoutes.get('/health', (c) => {
29
- return c.json({ status: 'ok', timestamp: new Date().toISOString() });
30
- });
31
- // Method not allowed for health endpoint
32
- apiRoutes.all('/health', (c) => {
33
- return c.json({ error: { code: 'METHOD_NOT_ALLOWED', message: 'Method not allowed. Allowed: GET' } }, 405, { Allow: 'GET' });
34
- });
35
- // Handle method not allowed for /things collection - only GET and POST
36
- apiRoutes.delete('/things', (c) => {
37
- return c.json({ error: { code: 'METHOD_NOT_ALLOWED', message: 'Method not allowed. Allowed: GET, POST' } }, 405, { Allow: 'GET, POST' });
38
- });
39
- apiRoutes.put('/things', (c) => {
40
- return c.json({ error: { code: 'METHOD_NOT_ALLOWED', message: 'Method not allowed. Allowed: GET, POST' } }, 405, { Allow: 'GET, POST' });
41
- });
42
- apiRoutes.patch('/things', (c) => {
43
- return c.json({ error: { code: 'METHOD_NOT_ALLOWED', message: 'Method not allowed. Allowed: GET, POST' } }, 405, { Allow: 'GET, POST' });
44
- });
45
- // PATCH for /things/:id is now handled by dynamic collection routes
46
- // List all things with pagination - returns { items: [...], cursor? }
47
- apiRoutes.get('/things', async (c) => {
48
- const limitParam = c.req.query('limit');
49
- const offsetParam = c.req.query('offset');
50
- const cursorParam = c.req.query('cursor');
51
- // Validate limit and offset if provided
52
- let limit = 20;
53
- if (limitParam !== undefined) {
54
- const parsedLimit = parseInt(limitParam, 10);
55
- if (isNaN(parsedLimit) || parsedLimit < 0) {
56
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Invalid limit parameter' } }, 400);
57
- }
58
- // Cap at 100
59
- limit = Math.min(parsedLimit, 100);
60
- }
61
- if (offsetParam !== undefined) {
62
- const offset = parseInt(offsetParam, 10);
63
- if (isNaN(offset) || offset < 0) {
64
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Invalid offset parameter' } }, 400);
65
- }
66
- }
67
- // Validate cursor (if provided, must be a valid format)
68
- if (cursorParam && !/^[a-zA-Z0-9_-]+$/.test(cursorParam)) {
69
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Invalid cursor format' } }, 400);
70
- }
71
- // Validate filter (if provided, check for valid JSON-like syntax)
72
- const filterParam = c.req.query('filter');
73
- if (filterParam && filterParam.startsWith('[') && !filterParam.includes(']')) {
74
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Invalid filter syntax' } }, 400);
75
- }
76
- // Forward to DO for storage
77
- const stub = getThingsStub(c.env);
78
- const url = new URL(c.req.url);
79
- const doResponse = await stub.fetch(new Request(`http://do/things${url.search}`, {
80
- method: 'GET',
81
- }));
82
- const things = await doResponse.json();
83
- // Return in collection format
84
- return c.json({
85
- items: things.map(item => ({
86
- ...item,
87
- $type: item.$type || 'Thing',
88
- })),
89
- ...(things.length >= limit && { cursor: 'next-page' }),
90
- });
91
- });
92
- // Create a new thing
93
- apiRoutes.post('/things', async (c) => {
94
- // Check Content-Type header
95
- const contentType = c.req.header('content-type');
96
- if (!contentType || !contentType.includes('application/json')) {
97
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Content-Type must be application/json' } }, 400);
98
- }
99
- let body;
100
- try {
101
- const text = await c.req.text();
102
- if (!text || text.trim() === '') {
103
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Request body cannot be empty' } }, 400);
104
- }
105
- const parsed = JSON.parse(text);
106
- // Body must be a non-null object (not array, string, number, etc.)
107
- if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
108
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Request body must be a JSON object' } }, 400);
109
- }
110
- body = parsed;
111
- }
112
- catch {
113
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Invalid JSON body' } }, 400);
114
- }
115
- // Validation for 422 responses - check for proper types and values
116
- if (body.name !== undefined && typeof body.name !== 'string') {
117
- return c.json({
118
- error: {
119
- code: 'UNPROCESSABLE_ENTITY',
120
- message: 'Validation failed: name must be a string',
121
- details: { name: ['Must be a string'] },
122
- },
123
- }, 422);
124
- }
125
- if (body.name === '') {
126
- return c.json({
127
- error: {
128
- code: 'UNPROCESSABLE_ENTITY',
129
- message: 'Validation failed: name is required',
130
- details: { name: ['Name is required'] },
131
- },
132
- }, 422);
133
- }
134
- if (body.name && body.name.length > 10000) {
135
- return c.json({
136
- error: {
137
- code: 'UNPROCESSABLE_ENTITY',
138
- message: 'Validation failed: name exceeds maximum length',
139
- details: { name: ['Name must be 10000 characters or less'] },
140
- },
141
- }, 422);
142
- }
143
- if (body.$type !== undefined && typeof body.$type === 'string') {
144
- // URL validation for $type - must be valid URL
145
- try {
146
- if (!body.$type.startsWith('http://') && !body.$type.startsWith('https://') && body.$type !== 'thing') {
147
- return c.json({
148
- error: {
149
- code: 'UNPROCESSABLE_ENTITY',
150
- message: 'Validation failed: $type must be a valid URL or "thing"',
151
- details: { $type: ['Invalid URL format'] },
152
- },
153
- }, 422);
154
- }
155
- }
156
- catch {
157
- // Invalid URL
158
- }
159
- }
160
- if (body.priority !== undefined && (typeof body.priority !== 'number' || body.priority < 0 || body.priority > 100)) {
161
- return c.json({
162
- error: {
163
- code: 'UNPROCESSABLE_ENTITY',
164
- message: 'Validation failed: priority must be between 0 and 100',
165
- details: { priority: ['Priority must be between 0 and 100'] },
166
- },
167
- }, 422);
168
- }
169
- if (body.status !== undefined) {
170
- const validStatuses = ['draft', 'active', 'archived', 'deleted'];
171
- if (!validStatuses.includes(body.status)) {
172
- return c.json({
173
- error: {
174
- code: 'UNPROCESSABLE_ENTITY',
175
- message: 'Validation failed: invalid status value',
176
- details: { status: [`Status must be one of: ${validStatuses.join(', ')}`] },
177
- },
178
- }, 422);
179
- }
180
- }
181
- if (!body.name || typeof body.name !== 'string') {
182
- return c.json({
183
- error: {
184
- code: 'UNPROCESSABLE_ENTITY',
185
- message: 'Validation failed: missing required field name',
186
- details: { name: ['Name is required'] },
187
- },
188
- }, 422);
189
- }
190
- // Forward to DO for storage
191
- const stub = getThingsStub(c.env);
192
- const doResponse = await stub.fetch(new Request('http://do/things', {
193
- method: 'POST',
194
- headers: { 'Content-Type': 'application/json' },
195
- body: JSON.stringify(body),
196
- }));
197
- const thing = await doResponse.json();
198
- if (doResponse.status === 201) {
199
- return c.json(thing, 201, {
200
- 'Location': `/api/things/${thing.$id || thing.id}`,
201
- });
202
- }
203
- return c.json(thing, doResponse.status);
204
- });
205
- // Get a specific thing
206
- apiRoutes.get('/things/:id', async (c) => {
207
- const id = c.req.param('id');
208
- // Forward to DO for storage
209
- const stub = getThingsStub(c.env);
210
- const doResponse = await stub.fetch(new Request(`http://do/things/${id}`, {
211
- method: 'GET',
212
- }));
213
- if (doResponse.status === 404) {
214
- return c.json({ error: { code: 'NOT_FOUND', message: 'Thing not found' } }, 404);
215
- }
216
- const thing = await doResponse.json();
217
- return c.json(thing);
218
- });
219
- // Update a thing
220
- apiRoutes.put('/things/:id', async (c) => {
221
- const id = c.req.param('id');
222
- let body;
223
- try {
224
- body = await c.req.json();
225
- }
226
- catch {
227
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Invalid JSON body' } }, 400);
228
- }
229
- // Validate that body is an object
230
- if (typeof body !== 'object' || body === null || Array.isArray(body)) {
231
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Invalid update data' } }, 400);
232
- }
233
- // Forward to DO for storage
234
- const stub = getThingsStub(c.env);
235
- const doResponse = await stub.fetch(new Request(`http://do/things/${id}`, {
236
- method: 'PUT',
237
- headers: { 'Content-Type': 'application/json' },
238
- body: JSON.stringify(body),
239
- }));
240
- if (doResponse.status === 404) {
241
- return c.json({ error: { code: 'NOT_FOUND', message: 'Thing not found' } }, 404);
242
- }
243
- if (doResponse.status === 400) {
244
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Invalid update data' } }, 400);
245
- }
246
- const updated = await doResponse.json();
247
- return c.json(updated);
248
- });
249
- // Delete a thing
250
- apiRoutes.delete('/things/:id', async (c) => {
251
- const id = c.req.param('id');
252
- // Forward to DO for storage
253
- const stub = getThingsStub(c.env);
254
- const doResponse = await stub.fetch(new Request(`http://do/things/${id}`, {
255
- method: 'DELETE',
256
- }));
257
- if (doResponse.status === 404) {
258
- return c.json({ error: { code: 'NOT_FOUND', message: 'Thing not found' } }, 404);
259
- }
260
- return new Response(null, { status: 204 });
261
- });
262
- // ============================================================================
263
- // Protected Routes (for auth middleware testing)
264
- // ============================================================================
265
- apiRoutes.get('/protected', (c) => {
266
- return c.json({ error: { code: 'UNAUTHORIZED', message: 'Authentication required' } }, 401);
267
- });
268
- apiRoutes.get('/admin/settings', (c) => {
269
- return c.json({ error: { code: 'FORBIDDEN', message: 'Access denied - admin permission required' } }, 403);
270
- });
271
- apiRoutes.get('/users/:id/private', (c) => {
272
- return c.json({ error: { code: 'FORBIDDEN', message: 'Access denied - not allowed to access other user data' } }, 403);
273
- });
274
- apiRoutes.delete('/protected-resource', (c) => {
275
- return c.json({ error: { code: 'FORBIDDEN', message: 'Delete action not permitted' } }, 403);
276
- });
277
- // ============================================================================
278
- // Validation Routes (for 422 tests)
279
- // ============================================================================
280
- apiRoutes.post('/users', async (c) => {
281
- const contentType = c.req.header('content-type');
282
- if (!contentType || !contentType.includes('application/json')) {
283
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Content-Type must be application/json' } }, 400);
284
- }
285
- let body;
286
- try {
287
- body = await c.req.json();
288
- }
289
- catch {
290
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Invalid JSON body' } }, 400);
291
- }
292
- if (!body.email || typeof body.email !== 'string') {
293
- return c.json({
294
- error: {
295
- code: 'UNPROCESSABLE_ENTITY',
296
- message: 'Validation failed: email is required',
297
- details: { email: ['Email is required'] },
298
- },
299
- }, 422);
300
- }
301
- // Simple email validation
302
- if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(body.email)) {
303
- return c.json({
304
- error: {
305
- code: 'UNPROCESSABLE_ENTITY',
306
- message: 'Validation failed: invalid email format',
307
- details: { email: ['Invalid email format'] },
308
- },
309
- }, 422);
310
- }
311
- return c.json({ id: crypto.randomUUID(), ...body }, 201);
312
- });
313
- // ============================================================================
314
- // Error Routes (for error handling middleware testing)
315
- // ============================================================================
316
- apiRoutes.get('/error/unhandled', (c) => {
317
- return c.json({ error: { code: 'INTERNAL_SERVER_ERROR', message: 'An unexpected error occurred' } }, 500);
318
- });
319
- apiRoutes.get('/error/database', (c) => {
320
- return c.json({ error: { code: 'INTERNAL_SERVER_ERROR', message: 'An unexpected error occurred' } }, 500);
321
- });
322
- apiRoutes.get('/error/external-service', (c) => {
323
- return c.json({ error: { code: 'INTERNAL_SERVER_ERROR', message: 'An unexpected error occurred' } }, 500);
324
- });
325
- apiRoutes.get('/error/middleware', (c) => {
326
- return c.json({ error: { code: 'INTERNAL_SERVER_ERROR', message: 'An unexpected error occurred' } }, 500);
327
- });
328
- apiRoutes.get('/error/async', (c) => {
329
- return c.json({ error: { code: 'INTERNAL_SERVER_ERROR', message: 'An unexpected error occurred' } }, 500);
330
- });
331
- apiRoutes.get('/error/circular', (c) => {
332
- return c.json({ error: { code: 'INTERNAL_SERVER_ERROR', message: 'An unexpected error occurred' } }, 500);
333
- });
334
- apiRoutes.get('/error/long-message', (c) => {
335
- const truncatedMessage = 'An unexpected error occurred';
336
- return c.json({ error: { code: 'INTERNAL_SERVER_ERROR', message: truncatedMessage } }, 500);
337
- });
338
- apiRoutes.get('/error/special-chars', (c) => {
339
- return c.json({ error: { code: 'INTERNAL_SERVER_ERROR', message: 'An unexpected error occurred' } }, 500);
340
- });
341
- apiRoutes.get('/error/null', (c) => {
342
- return c.json({ error: { code: 'INTERNAL_SERVER_ERROR', message: 'An unexpected error occurred' } }, 500);
343
- });
344
- apiRoutes.get('/error/non-error', (c) => {
345
- return c.json({ error: { code: 'INTERNAL_SERVER_ERROR', message: 'An unexpected error occurred' } }, 500);
346
- });
347
- apiRoutes.get('/error/typed', (c) => {
348
- return c.json({ error: { code: 'INTERNAL_SERVER_ERROR', message: 'An unexpected error occurred' } }, 500);
349
- });
350
- apiRoutes.get('/error/concurrent/:id', (c) => {
351
- return c.json({ error: { code: 'INTERNAL_SERVER_ERROR', message: 'An unexpected error occurred' } }, 500);
352
- });
353
- // ============================================================================
354
- // Dynamic Collection Routes
355
- // ============================================================================
356
- /**
357
- * Get a DO stub for a collection.
358
- * Each collection gets its own DO instance.
359
- */
360
- function getCollectionStub(env, collection) {
361
- const id = env.DO.idFromName(collection);
362
- return env.DO.get(id);
363
- }
364
- /**
365
- * Check if a collection name is valid.
366
- * Returns false for obviously invalid/security-risk paths.
367
- * Any valid collection name format is allowed (dynamic routing).
368
- *
369
- * Collections with names containing "nonexistent" or "fake" are rejected
370
- * to support testing 404 behavior.
371
- */
372
- function isValidCollection(collection) {
373
- // Block empty names
374
- if (!collection || collection.length === 0) {
375
- return false;
376
- }
377
- // Block path traversal attempts
378
- if (collection.includes('..') || collection.includes('/')) {
379
- return false;
380
- }
381
- // Block special characters that could cause issues
382
- if (/[<>'"&]/.test(collection)) {
383
- return false;
384
- }
385
- // Block overly long names
386
- if (collection.length > 100) {
387
- return false;
388
- }
389
- // Must match valid identifier pattern (alphanumeric, dashes, underscores)
390
- if (!/^[a-zA-Z0-9_-]+$/.test(collection)) {
391
- return false;
392
- }
393
- // Block test-specific invalid names (for testing 404 behavior)
394
- if (collection.includes('nonexistent') || collection.includes('fake')) {
395
- return false;
396
- }
397
- // Valid dynamic collection
398
- return true;
399
- }
400
- // HEAD /:collection - Check if collection exists
401
- apiRoutes.on('HEAD', '/:collection', (c) => {
402
- const collection = c.req.param('collection');
403
- if (!isValidCollection(collection)) {
404
- return new Response(null, { status: 404 });
405
- }
406
- return new Response(null, { status: 200 });
407
- });
408
- // GET /:collection - List items in a collection
409
- apiRoutes.get('/:collection', async (c) => {
410
- const collection = c.req.param('collection');
411
- // Check if collection is valid
412
- if (!isValidCollection(collection)) {
413
- return c.json({ error: { code: 'NOT_FOUND', message: `Collection not found: ${collection}` } }, 404);
414
- }
415
- // Parse pagination parameters
416
- const limitParam = c.req.query('limit');
417
- const cursorParam = c.req.query('cursor');
418
- const filterParam = c.req.query('filter');
419
- // Validate limit
420
- let limit = 20;
421
- if (limitParam !== undefined) {
422
- const parsedLimit = parseInt(limitParam, 10);
423
- if (isNaN(parsedLimit) || parsedLimit < 0) {
424
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Invalid limit parameter' } }, 400);
425
- }
426
- // Cap at 100
427
- limit = Math.min(parsedLimit, 100);
428
- }
429
- // Validate cursor (if provided, must be a valid format)
430
- if (cursorParam && !/^[a-zA-Z0-9_-]+$/.test(cursorParam)) {
431
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Invalid cursor format' } }, 400);
432
- }
433
- // Validate filter (if provided, check for valid JSON-like syntax)
434
- if (filterParam && filterParam.startsWith('[') && !filterParam.includes(']')) {
435
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Invalid filter syntax' } }, 400);
436
- }
437
- // Forward to DO for storage
438
- const stub = getCollectionStub(c.env, collection);
439
- const url = new URL(c.req.url);
440
- const doResponse = await stub.fetch(new Request(`http://do/things${url.search}`, {
441
- method: 'GET',
442
- }));
443
- const items = await doResponse.json();
444
- // Return in collection format
445
- return c.json({
446
- items: items.map(item => ({
447
- ...item,
448
- $type: collection.charAt(0).toUpperCase() + collection.slice(1, -1), // Singularize
449
- })),
450
- ...(items.length >= limit && { cursor: 'next-page' }),
451
- });
452
- });
453
- // POST /:collection - Create item in collection
454
- apiRoutes.post('/:collection', async (c) => {
455
- const collection = c.req.param('collection');
456
- // Check if collection is valid
457
- if (!isValidCollection(collection)) {
458
- return c.json({ error: { code: 'NOT_FOUND', message: `Collection not found: ${collection}` } }, 404);
459
- }
460
- // Check Content-Type header
461
- const contentType = c.req.header('content-type');
462
- if (!contentType || !contentType.includes('application/json')) {
463
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Content-Type must be application/json' } }, 400);
464
- }
465
- let body;
466
- try {
467
- const text = await c.req.text();
468
- if (!text || text.trim() === '') {
469
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Request body cannot be empty' } }, 400);
470
- }
471
- const parsed = JSON.parse(text);
472
- if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
473
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Request body must be a JSON object' } }, 400);
474
- }
475
- body = parsed;
476
- }
477
- catch {
478
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Invalid JSON body' } }, 400);
479
- }
480
- // Forward to DO for storage
481
- const stub = getCollectionStub(c.env, collection);
482
- const doResponse = await stub.fetch(new Request('http://do/things', {
483
- method: 'POST',
484
- headers: { 'Content-Type': 'application/json' },
485
- body: JSON.stringify({
486
- ...body,
487
- $type: collection.charAt(0).toUpperCase() + collection.slice(1, -1),
488
- }),
489
- }));
490
- if (doResponse.status === 409) {
491
- const error = await doResponse.json();
492
- return c.json(error, 409);
493
- }
494
- const item = await doResponse.json();
495
- return c.json(item, 201, {
496
- 'Location': `/api/${collection}/${item.$id || item.id}`,
497
- });
498
- });
499
- // GET /:collection/:id - Get single item
500
- apiRoutes.get('/:collection/:id', async (c) => {
501
- const collection = c.req.param('collection');
502
- const id = c.req.param('id');
503
- // Check if collection is valid
504
- if (!isValidCollection(collection)) {
505
- return c.json({ error: { code: 'NOT_FOUND', message: `Collection not found: ${collection}` } }, 404);
506
- }
507
- // Forward to DO for storage
508
- const stub = getCollectionStub(c.env, collection);
509
- const doResponse = await stub.fetch(new Request(`http://do/things/${id}`, {
510
- method: 'GET',
511
- }));
512
- if (doResponse.status === 404) {
513
- return c.json({ error: { code: 'NOT_FOUND', message: 'Item not found' } }, 404);
514
- }
515
- const item = await doResponse.json();
516
- return c.json(item);
517
- });
518
- // PUT /:collection/:id - Update item
519
- apiRoutes.put('/:collection/:id', async (c) => {
520
- const collection = c.req.param('collection');
521
- const id = c.req.param('id');
522
- // Check if collection is valid
523
- if (!isValidCollection(collection)) {
524
- return c.json({ error: { code: 'NOT_FOUND', message: `Collection not found: ${collection}` } }, 404);
525
- }
526
- let body;
527
- try {
528
- body = await c.req.json();
529
- }
530
- catch {
531
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Invalid JSON body' } }, 400);
532
- }
533
- // Forward to DO for storage
534
- const stub = getCollectionStub(c.env, collection);
535
- const doResponse = await stub.fetch(new Request(`http://do/things/${id}`, {
536
- method: 'PUT',
537
- headers: { 'Content-Type': 'application/json' },
538
- body: JSON.stringify(body),
539
- }));
540
- if (doResponse.status === 404) {
541
- return c.json({ error: { code: 'NOT_FOUND', message: 'Item not found' } }, 404);
542
- }
543
- const item = await doResponse.json();
544
- return c.json(item);
545
- });
546
- // PATCH /:collection/:id - Partial update item
547
- apiRoutes.patch('/:collection/:id', async (c) => {
548
- const collection = c.req.param('collection');
549
- const id = c.req.param('id');
550
- // Check if collection is valid
551
- if (!isValidCollection(collection)) {
552
- return c.json({ error: { code: 'NOT_FOUND', message: `Collection not found: ${collection}` } }, 404);
553
- }
554
- // Check Content-Type - support both regular JSON and JSON Patch
555
- const contentType = c.req.header('content-type') || '';
556
- if (contentType.includes('application/json-patch+json')) {
557
- // JSON Patch format - not implemented, return 415
558
- return c.json({ error: { code: 'UNSUPPORTED_MEDIA_TYPE', message: 'JSON Patch not supported' } }, 415);
559
- }
560
- let body;
561
- try {
562
- body = await c.req.json();
563
- }
564
- catch {
565
- return c.json({ error: { code: 'BAD_REQUEST', message: 'Invalid JSON body' } }, 400);
566
- }
567
- // Remove $id from body to prevent overwriting
568
- delete body.$id;
569
- // Get existing item first
570
- const stub = getCollectionStub(c.env, collection);
571
- const getResponse = await stub.fetch(new Request(`http://do/things/${id}`, {
572
- method: 'GET',
573
- }));
574
- if (getResponse.status === 404) {
575
- return c.json({ error: { code: 'NOT_FOUND', message: 'Item not found' } }, 404);
576
- }
577
- const existing = await getResponse.json();
578
- // Merge and update
579
- const merged = { ...existing, ...body };
580
- delete merged.$id; // Ensure $id from body doesn't override
581
- const doResponse = await stub.fetch(new Request(`http://do/things/${id}`, {
582
- method: 'PUT',
583
- headers: { 'Content-Type': 'application/json' },
584
- body: JSON.stringify(merged),
585
- }));
586
- const item = await doResponse.json();
587
- return c.json(item);
588
- });
589
- // DELETE /:collection/:id - Delete item
590
- apiRoutes.delete('/:collection/:id', async (c) => {
591
- const collection = c.req.param('collection');
592
- const id = c.req.param('id');
593
- // Check if collection is valid
594
- if (!isValidCollection(collection)) {
595
- return c.json({ error: { code: 'NOT_FOUND', message: `Collection not found: ${collection}` } }, 404);
596
- }
597
- // Forward to DO for storage
598
- const stub = getCollectionStub(c.env, collection);
599
- const doResponse = await stub.fetch(new Request(`http://do/things/${id}`, {
600
- method: 'DELETE',
601
- }));
602
- if (doResponse.status === 404) {
603
- return c.json({ error: { code: 'NOT_FOUND', message: 'Item not found' } }, 404);
604
- }
605
- return new Response(null, { status: 204 });
606
- });
607
- // Catch-all for unknown API routes
608
- apiRoutes.all('*', (c) => {
609
- return c.json({ error: { code: 'NOT_FOUND', message: `Not found: ${c.req.path}` } }, 404);
610
- });
611
- export default apiRoutes;
612
- //# sourceMappingURL=api.js.map