dotdo 0.0.1 → 0.0.2

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 (727) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +446 -315
  3. package/dist/ai/index.js +19 -0
  4. package/dist/ai/index.js.map +1 -0
  5. package/dist/ai/template-literals.js +852 -0
  6. package/dist/ai/template-literals.js.map +1 -0
  7. package/dist/api/analytics/router.js +601 -0
  8. package/dist/api/analytics/router.js.map +1 -0
  9. package/dist/api/index.js +158 -0
  10. package/dist/api/index.js.map +1 -0
  11. package/dist/api/middleware/auth-federation.js +573 -0
  12. package/dist/api/middleware/auth-federation.js.map +1 -0
  13. package/dist/api/middleware/auth.js +544 -0
  14. package/dist/api/middleware/auth.js.map +1 -0
  15. package/dist/api/middleware/error-handling.js +176 -0
  16. package/dist/api/middleware/error-handling.js.map +1 -0
  17. package/dist/api/middleware/request-id.js +21 -0
  18. package/dist/api/middleware/request-id.js.map +1 -0
  19. package/dist/api/pages.js +1180 -0
  20. package/dist/api/pages.js.map +1 -0
  21. package/dist/api/routes/api.js +612 -0
  22. package/dist/api/routes/api.js.map +1 -0
  23. package/dist/api/routes/browsers.js +471 -0
  24. package/dist/api/routes/browsers.js.map +1 -0
  25. package/dist/api/routes/do.js +188 -0
  26. package/dist/api/routes/do.js.map +1 -0
  27. package/dist/api/routes/mcp.js +459 -0
  28. package/dist/api/routes/mcp.js.map +1 -0
  29. package/dist/api/routes/obs.js +445 -0
  30. package/dist/api/routes/obs.js.map +1 -0
  31. package/dist/api/routes/openapi.js +794 -0
  32. package/dist/api/routes/openapi.js.map +1 -0
  33. package/dist/api/routes/rpc.js +1103 -0
  34. package/dist/api/routes/rpc.js.map +1 -0
  35. package/dist/api/routes/sandboxes.js +389 -0
  36. package/dist/api/routes/sandboxes.js.map +1 -0
  37. package/dist/api/test-do.js +38 -0
  38. package/dist/api/test-do.js.map +1 -0
  39. package/dist/api/types.js +11 -0
  40. package/dist/api/types.js.map +1 -0
  41. package/dist/cli/bin.js +2 -0
  42. package/dist/cli/main.js +52342 -0
  43. package/dist/db/actions.js +212 -0
  44. package/dist/db/actions.js.map +1 -0
  45. package/dist/db/auth.js +506 -0
  46. package/dist/db/auth.js.map +1 -0
  47. package/dist/db/branches.js +65 -0
  48. package/dist/db/branches.js.map +1 -0
  49. package/dist/db/clickhouse.js +1074 -0
  50. package/dist/db/clickhouse.js.map +1 -0
  51. package/dist/db/dlq.js +39 -0
  52. package/dist/db/dlq.js.map +1 -0
  53. package/dist/db/events.js +28 -0
  54. package/dist/db/events.js.map +1 -0
  55. package/dist/db/exec.js +64 -0
  56. package/dist/db/exec.js.map +1 -0
  57. package/dist/db/files.js +85 -0
  58. package/dist/db/files.js.map +1 -0
  59. package/dist/db/flags.js +24 -0
  60. package/dist/db/flags.js.map +1 -0
  61. package/dist/db/git.js +116 -0
  62. package/dist/db/git.js.map +1 -0
  63. package/dist/db/iceberg/inverted-index.js +862 -0
  64. package/dist/db/iceberg/inverted-index.js.map +1 -0
  65. package/dist/db/iceberg/puffin.js +878 -0
  66. package/dist/db/iceberg/puffin.js.map +1 -0
  67. package/dist/db/iceberg/search-manifest.js +422 -0
  68. package/dist/db/iceberg/search-manifest.js.map +1 -0
  69. package/dist/db/iceberg/types.js +8 -0
  70. package/dist/db/iceberg/types.js.map +1 -0
  71. package/dist/db/index.js +121 -0
  72. package/dist/db/index.js.map +1 -0
  73. package/dist/db/integrations.js +368 -0
  74. package/dist/db/integrations.js.map +1 -0
  75. package/dist/db/json-indexes.js +332 -0
  76. package/dist/db/json-indexes.js.map +1 -0
  77. package/dist/db/linked-accounts.js +287 -0
  78. package/dist/db/linked-accounts.js.map +1 -0
  79. package/dist/db/nouns.js +183 -0
  80. package/dist/db/nouns.js.map +1 -0
  81. package/dist/db/objects.js +170 -0
  82. package/dist/db/objects.js.map +1 -0
  83. package/dist/db/primitives/dag-scheduler/index.js +869 -0
  84. package/dist/db/primitives/dag-scheduler/index.js.map +1 -0
  85. package/dist/db/primitives/exactly-once-context.js +237 -0
  86. package/dist/db/primitives/exactly-once-context.js.map +1 -0
  87. package/dist/db/primitives/index.js +62 -0
  88. package/dist/db/primitives/index.js.map +1 -0
  89. package/dist/db/primitives/keyed-router.js +145 -0
  90. package/dist/db/primitives/keyed-router.js.map +1 -0
  91. package/dist/db/primitives/observability.js +162 -0
  92. package/dist/db/primitives/observability.js.map +1 -0
  93. package/dist/db/primitives/schema-evolution.js +643 -0
  94. package/dist/db/primitives/schema-evolution.js.map +1 -0
  95. package/dist/db/primitives/stateful-operator/index.js +770 -0
  96. package/dist/db/primitives/stateful-operator/index.js.map +1 -0
  97. package/dist/db/primitives/temporal-store.js +306 -0
  98. package/dist/db/primitives/temporal-store.js.map +1 -0
  99. package/dist/db/primitives/typed-column-store.js +1229 -0
  100. package/dist/db/primitives/typed-column-store.js.map +1 -0
  101. package/dist/db/primitives/utils/duration.js +162 -0
  102. package/dist/db/primitives/utils/duration.js.map +1 -0
  103. package/dist/db/primitives/utils/murmur3.js +118 -0
  104. package/dist/db/primitives/utils/murmur3.js.map +1 -0
  105. package/dist/db/primitives/watermark-service.js +136 -0
  106. package/dist/db/primitives/watermark-service.js.map +1 -0
  107. package/dist/db/primitives/window-manager.js +764 -0
  108. package/dist/db/primitives/window-manager.js.map +1 -0
  109. package/dist/db/relationships.js +66 -0
  110. package/dist/db/relationships.js.map +1 -0
  111. package/dist/db/schema-minimal.js +61 -0
  112. package/dist/db/schema-minimal.js.map +1 -0
  113. package/dist/db/search.js +28 -0
  114. package/dist/db/search.js.map +1 -0
  115. package/dist/db/stores.js +1665 -0
  116. package/dist/db/stores.js.map +1 -0
  117. package/dist/db/things.js +297 -0
  118. package/dist/db/things.js.map +1 -0
  119. package/dist/db/vault.js +171 -0
  120. package/dist/db/vault.js.map +1 -0
  121. package/dist/db/verbs.js +102 -0
  122. package/dist/db/verbs.js.map +1 -0
  123. package/dist/do/base.js +48 -0
  124. package/dist/do/base.js.map +1 -0
  125. package/dist/do/bash.js +35 -0
  126. package/dist/do/bash.js.map +1 -0
  127. package/dist/do/fs.js +25 -0
  128. package/dist/do/fs.js.map +1 -0
  129. package/dist/do/full.js +61 -0
  130. package/dist/do/full.js.map +1 -0
  131. package/dist/do/git.js +28 -0
  132. package/dist/do/git.js.map +1 -0
  133. package/dist/do/index.js +52 -0
  134. package/dist/do/index.js.map +1 -0
  135. package/dist/do/tiny.js +31 -0
  136. package/dist/do/tiny.js.map +1 -0
  137. package/dist/lib/DOAuth.js +261 -0
  138. package/dist/lib/DOAuth.js.map +1 -0
  139. package/dist/lib/DODispatcher.js +72 -0
  140. package/dist/lib/DODispatcher.js.map +1 -0
  141. package/dist/lib/Modifier.js +189 -0
  142. package/dist/lib/Modifier.js.map +1 -0
  143. package/dist/lib/StateStorage.js +403 -0
  144. package/dist/lib/StateStorage.js.map +1 -0
  145. package/dist/lib/TypeRegistry.js +122 -0
  146. package/dist/lib/TypeRegistry.js.map +1 -0
  147. package/dist/lib/agent/tools/bash.js +336 -0
  148. package/dist/lib/agent/tools/bash.js.map +1 -0
  149. package/dist/lib/agent/tools/edit.js +157 -0
  150. package/dist/lib/agent/tools/edit.js.map +1 -0
  151. package/dist/lib/agent/tools/glob.js +137 -0
  152. package/dist/lib/agent/tools/glob.js.map +1 -0
  153. package/dist/lib/agent/tools/grep.js +315 -0
  154. package/dist/lib/agent/tools/grep.js.map +1 -0
  155. package/dist/lib/agent/tools/index.js +71 -0
  156. package/dist/lib/agent/tools/index.js.map +1 -0
  157. package/dist/lib/agent/tools/read.js +212 -0
  158. package/dist/lib/agent/tools/read.js.map +1 -0
  159. package/dist/lib/agent/tools/types.js +197 -0
  160. package/dist/lib/agent/tools/types.js.map +1 -0
  161. package/dist/lib/agent/tools/write.js +159 -0
  162. package/dist/lib/agent/tools/write.js.map +1 -0
  163. package/dist/lib/ai/gateway.js +247 -0
  164. package/dist/lib/ai/gateway.js.map +1 -0
  165. package/dist/lib/ai/tool-loop-agent.js +591 -0
  166. package/dist/lib/ai/tool-loop-agent.js.map +1 -0
  167. package/dist/lib/auto-wiring.js +439 -0
  168. package/dist/lib/auto-wiring.js.map +1 -0
  169. package/dist/lib/browse/browserbase.js +163 -0
  170. package/dist/lib/browse/browserbase.js.map +1 -0
  171. package/dist/lib/browse/cloudflare.js +144 -0
  172. package/dist/lib/browse/cloudflare.js.map +1 -0
  173. package/dist/lib/browse/index.js +62 -0
  174. package/dist/lib/browse/index.js.map +1 -0
  175. package/dist/lib/browse/types.js +13 -0
  176. package/dist/lib/browse/types.js.map +1 -0
  177. package/dist/lib/cache/index.js +37 -0
  178. package/dist/lib/cache/index.js.map +1 -0
  179. package/dist/lib/cache/visibility.js +638 -0
  180. package/dist/lib/cache/visibility.js.map +1 -0
  181. package/dist/lib/capabilities.js +268 -0
  182. package/dist/lib/capabilities.js.map +1 -0
  183. package/dist/lib/channels/base.js +106 -0
  184. package/dist/lib/channels/base.js.map +1 -0
  185. package/dist/lib/channels/discord.js +94 -0
  186. package/dist/lib/channels/discord.js.map +1 -0
  187. package/dist/lib/channels/email.js +204 -0
  188. package/dist/lib/channels/email.js.map +1 -0
  189. package/dist/lib/channels/index.js +90 -0
  190. package/dist/lib/channels/index.js.map +1 -0
  191. package/dist/lib/channels/mdxui-chat.js +95 -0
  192. package/dist/lib/channels/mdxui-chat.js.map +1 -0
  193. package/dist/lib/channels/slack-blockkit.js +121 -0
  194. package/dist/lib/channels/slack-blockkit.js.map +1 -0
  195. package/dist/lib/channels/types.js +7 -0
  196. package/dist/lib/channels/types.js.map +1 -0
  197. package/dist/lib/cloudflare/ai.js +654 -0
  198. package/dist/lib/cloudflare/ai.js.map +1 -0
  199. package/dist/lib/cloudflare/index.js +88 -0
  200. package/dist/lib/cloudflare/index.js.map +1 -0
  201. package/dist/lib/cloudflare/kv.js +342 -0
  202. package/dist/lib/cloudflare/kv.js.map +1 -0
  203. package/dist/lib/cloudflare/queues.js +434 -0
  204. package/dist/lib/cloudflare/queues.js.map +1 -0
  205. package/dist/lib/cloudflare/r2.js +604 -0
  206. package/dist/lib/cloudflare/r2.js.map +1 -0
  207. package/dist/lib/cloudflare/vectorize.js +494 -0
  208. package/dist/lib/cloudflare/vectorize.js.map +1 -0
  209. package/dist/lib/cloudflare/workflows.js +569 -0
  210. package/dist/lib/cloudflare/workflows.js.map +1 -0
  211. package/dist/lib/colo/caching.js +196 -0
  212. package/dist/lib/colo/caching.js.map +1 -0
  213. package/dist/lib/colo/detection.js +194 -0
  214. package/dist/lib/colo/detection.js.map +1 -0
  215. package/dist/lib/colo/external-data.js +219 -0
  216. package/dist/lib/colo/external-data.js.map +1 -0
  217. package/dist/lib/colo/globe-data.js +179 -0
  218. package/dist/lib/colo/globe-data.js.map +1 -0
  219. package/dist/lib/colo/index.js +16 -0
  220. package/dist/lib/colo/index.js.map +1 -0
  221. package/dist/lib/decorators.js +37 -0
  222. package/dist/lib/decorators.js.map +1 -0
  223. package/dist/lib/discovery.js +81 -0
  224. package/dist/lib/discovery.js.map +1 -0
  225. package/dist/lib/executors/AgenticFunctionExecutor.js +619 -0
  226. package/dist/lib/executors/AgenticFunctionExecutor.js.map +1 -0
  227. package/dist/lib/executors/BaseFunctionExecutor.js +328 -0
  228. package/dist/lib/executors/BaseFunctionExecutor.js.map +1 -0
  229. package/dist/lib/executors/CascadeExecutor.js +418 -0
  230. package/dist/lib/executors/CascadeExecutor.js.map +1 -0
  231. package/dist/lib/executors/CodeFunctionExecutor.js +904 -0
  232. package/dist/lib/executors/CodeFunctionExecutor.js.map +1 -0
  233. package/dist/lib/executors/GenerativeFunctionExecutor.js +904 -0
  234. package/dist/lib/executors/GenerativeFunctionExecutor.js.map +1 -0
  235. package/dist/lib/executors/HumanFunctionExecutor.js +884 -0
  236. package/dist/lib/executors/HumanFunctionExecutor.js.map +1 -0
  237. package/dist/lib/executors/ParallelStepExecutor.js +308 -0
  238. package/dist/lib/executors/ParallelStepExecutor.js.map +1 -0
  239. package/dist/lib/executors/types.js +12 -0
  240. package/dist/lib/executors/types.js.map +1 -0
  241. package/dist/lib/experiments.js +89 -0
  242. package/dist/lib/experiments.js.map +1 -0
  243. package/dist/lib/flags/store.js +262 -0
  244. package/dist/lib/flags/store.js.map +1 -0
  245. package/dist/lib/functions/FunctionComposition.js +467 -0
  246. package/dist/lib/functions/FunctionComposition.js.map +1 -0
  247. package/dist/lib/functions/FunctionMiddleware.js +457 -0
  248. package/dist/lib/functions/FunctionMiddleware.js.map +1 -0
  249. package/dist/lib/functions/FunctionRegistry.js +426 -0
  250. package/dist/lib/functions/FunctionRegistry.js.map +1 -0
  251. package/dist/lib/functions/createFunction.js +1048 -0
  252. package/dist/lib/functions/createFunction.js.map +1 -0
  253. package/dist/lib/humans/index.js +68 -0
  254. package/dist/lib/humans/index.js.map +1 -0
  255. package/dist/lib/humans/templates.js +117 -0
  256. package/dist/lib/humans/templates.js.map +1 -0
  257. package/dist/lib/identity.js +98 -0
  258. package/dist/lib/identity.js.map +1 -0
  259. package/dist/lib/index.js +9 -0
  260. package/dist/lib/index.js.map +1 -0
  261. package/dist/lib/logging/error-logger.js +163 -0
  262. package/dist/lib/logging/error-logger.js.map +1 -0
  263. package/dist/lib/logging/index.js +160 -0
  264. package/dist/lib/logging/index.js.map +1 -0
  265. package/dist/lib/mixins/bash.js +825 -0
  266. package/dist/lib/mixins/bash.js.map +1 -0
  267. package/dist/lib/mixins/fs.js +648 -0
  268. package/dist/lib/mixins/fs.js.map +1 -0
  269. package/dist/lib/mixins/git.js +1011 -0
  270. package/dist/lib/mixins/git.js.map +1 -0
  271. package/dist/lib/mixins/index.js +29 -0
  272. package/dist/lib/mixins/index.js.map +1 -0
  273. package/dist/lib/mixins/npm.js +662 -0
  274. package/dist/lib/mixins/npm.js.map +1 -0
  275. package/dist/lib/noun-id.js +278 -0
  276. package/dist/lib/noun-id.js.map +1 -0
  277. package/dist/lib/rate-limit/sliding-window.js +148 -0
  278. package/dist/lib/rate-limit/sliding-window.js.map +1 -0
  279. package/dist/lib/rate-limit.js +110 -0
  280. package/dist/lib/rate-limit.js.map +1 -0
  281. package/dist/lib/rpc/bindings.js +548 -0
  282. package/dist/lib/rpc/bindings.js.map +1 -0
  283. package/dist/lib/rpc/index.js +64 -0
  284. package/dist/lib/rpc/index.js.map +1 -0
  285. package/dist/lib/safe-stringify.js +223 -0
  286. package/dist/lib/safe-stringify.js.map +1 -0
  287. package/dist/lib/sandbox/miniflare-sandbox.js +1007 -0
  288. package/dist/lib/sandbox/miniflare-sandbox.js.map +1 -0
  289. package/dist/lib/sqids.js +110 -0
  290. package/dist/lib/sqids.js.map +1 -0
  291. package/dist/lib/sql/adapters/index.js +10 -0
  292. package/dist/lib/sql/adapters/index.js.map +1 -0
  293. package/dist/lib/sql/adapters/node-sql-parser.js +552 -0
  294. package/dist/lib/sql/adapters/node-sql-parser.js.map +1 -0
  295. package/dist/lib/sql/adapters/pgsql-parser.js +1189 -0
  296. package/dist/lib/sql/adapters/pgsql-parser.js.map +1 -0
  297. package/dist/lib/sql/index.js +277 -0
  298. package/dist/lib/sql/index.js.map +1 -0
  299. package/dist/lib/sql/types.js +56 -0
  300. package/dist/lib/sql/types.js.map +1 -0
  301. package/dist/lib/type-classifier.js +126 -0
  302. package/dist/lib/type-classifier.js.map +1 -0
  303. package/dist/lib/utils/html.js +47 -0
  304. package/dist/lib/utils/html.js.map +1 -0
  305. package/dist/lib/validation.js +48 -0
  306. package/dist/lib/validation.js.map +1 -0
  307. package/dist/lib/vault/store.js +411 -0
  308. package/dist/lib/vault/store.js.map +1 -0
  309. package/dist/metrics/hunch.js +739 -0
  310. package/dist/metrics/hunch.js.map +1 -0
  311. package/dist/objects/API.js +302 -0
  312. package/dist/objects/API.js.map +1 -0
  313. package/dist/objects/Agent.js +179 -0
  314. package/dist/objects/Agent.js.map +1 -0
  315. package/dist/objects/AgenticFunctionExecutor.js +8 -0
  316. package/dist/objects/AgenticFunctionExecutor.js.map +1 -0
  317. package/dist/objects/App.js +83 -0
  318. package/dist/objects/App.js.map +1 -0
  319. package/dist/objects/Browser.js +884 -0
  320. package/dist/objects/Browser.js.map +1 -0
  321. package/dist/objects/Business.js +107 -0
  322. package/dist/objects/Business.js.map +1 -0
  323. package/dist/objects/CLI.js +221 -0
  324. package/dist/objects/CLI.js.map +1 -0
  325. package/dist/objects/CodeFunctionExecutor.js +8 -0
  326. package/dist/objects/CodeFunctionExecutor.js.map +1 -0
  327. package/dist/objects/Collection.js +161 -0
  328. package/dist/objects/Collection.js.map +1 -0
  329. package/dist/objects/DO.js +41 -0
  330. package/dist/objects/DO.js.map +1 -0
  331. package/dist/objects/DOBase.js +2309 -0
  332. package/dist/objects/DOBase.js.map +1 -0
  333. package/dist/objects/DOFull.js +1676 -0
  334. package/dist/objects/DOFull.js.map +1 -0
  335. package/dist/objects/DOTiny.js +207 -0
  336. package/dist/objects/DOTiny.js.map +1 -0
  337. package/dist/objects/Directory.js +199 -0
  338. package/dist/objects/Directory.js.map +1 -0
  339. package/dist/objects/Entity.js +413 -0
  340. package/dist/objects/Entity.js.map +1 -0
  341. package/dist/objects/Function.js +116 -0
  342. package/dist/objects/Function.js.map +1 -0
  343. package/dist/objects/Human.js +231 -0
  344. package/dist/objects/Human.js.map +1 -0
  345. package/dist/objects/HumanFunctionExecutor.js +8 -0
  346. package/dist/objects/HumanFunctionExecutor.js.map +1 -0
  347. package/dist/objects/IcebergMetadataDO.js +938 -0
  348. package/dist/objects/IcebergMetadataDO.js.map +1 -0
  349. package/dist/objects/IntegrationsDO.js +1174 -0
  350. package/dist/objects/IntegrationsDO.js.map +1 -0
  351. package/dist/objects/ObservabilityBroadcaster.js +149 -0
  352. package/dist/objects/ObservabilityBroadcaster.js.map +1 -0
  353. package/dist/objects/Package.js +154 -0
  354. package/dist/objects/Package.js.map +1 -0
  355. package/dist/objects/Product.js +193 -0
  356. package/dist/objects/Product.js.map +1 -0
  357. package/dist/objects/SDK.js +152 -0
  358. package/dist/objects/SDK.js.map +1 -0
  359. package/dist/objects/SaaS.js +235 -0
  360. package/dist/objects/SaaS.js.map +1 -0
  361. package/dist/objects/SandboxDO.js +759 -0
  362. package/dist/objects/SandboxDO.js.map +1 -0
  363. package/dist/objects/Service.js +337 -0
  364. package/dist/objects/Service.js.map +1 -0
  365. package/dist/objects/Site.js +80 -0
  366. package/dist/objects/Site.js.map +1 -0
  367. package/dist/objects/Startup.js +479 -0
  368. package/dist/objects/Startup.js.map +1 -0
  369. package/dist/objects/ThingsDO.js +170 -0
  370. package/dist/objects/ThingsDO.js.map +1 -0
  371. package/dist/objects/VectorShardDO.js +648 -0
  372. package/dist/objects/VectorShardDO.js.map +1 -0
  373. package/dist/objects/Worker.js +144 -0
  374. package/dist/objects/Worker.js.map +1 -0
  375. package/dist/objects/Workflow.js +196 -0
  376. package/dist/objects/Workflow.js.map +1 -0
  377. package/dist/objects/WorkflowFactory.js +313 -0
  378. package/dist/objects/WorkflowFactory.js.map +1 -0
  379. package/dist/objects/WorkflowRuntime.js +863 -0
  380. package/dist/objects/WorkflowRuntime.js.map +1 -0
  381. package/dist/objects/circuit-breaker-bulkhead.js +178 -0
  382. package/dist/objects/circuit-breaker-bulkhead.js.map +1 -0
  383. package/dist/objects/createFunction.js +934 -0
  384. package/dist/objects/createFunction.js.map +1 -0
  385. package/dist/objects/index.js +80 -0
  386. package/dist/objects/index.js.map +1 -0
  387. package/dist/objects/lifecycle/Branch.js +275 -0
  388. package/dist/objects/lifecycle/Branch.js.map +1 -0
  389. package/dist/objects/lifecycle/Clone.js +1499 -0
  390. package/dist/objects/lifecycle/Clone.js.map +1 -0
  391. package/dist/objects/lifecycle/Compact.js +237 -0
  392. package/dist/objects/lifecycle/Compact.js.map +1 -0
  393. package/dist/objects/lifecycle/Promote.js +476 -0
  394. package/dist/objects/lifecycle/Promote.js.map +1 -0
  395. package/dist/objects/lifecycle/Shard.js +560 -0
  396. package/dist/objects/lifecycle/Shard.js.map +1 -0
  397. package/dist/objects/lifecycle/index.js +15 -0
  398. package/dist/objects/lifecycle/index.js.map +1 -0
  399. package/dist/objects/lifecycle/types.js +33 -0
  400. package/dist/objects/lifecycle/types.js.map +1 -0
  401. package/dist/objects/mixins/infrastructure.js +171 -0
  402. package/dist/objects/mixins/infrastructure.js.map +1 -0
  403. package/dist/objects/modules/StoresModule.js +153 -0
  404. package/dist/objects/modules/StoresModule.js.map +1 -0
  405. package/dist/objects/persistence/checkpoint-manager.js +606 -0
  406. package/dist/objects/persistence/checkpoint-manager.js.map +1 -0
  407. package/dist/objects/persistence/index.js +72 -0
  408. package/dist/objects/persistence/index.js.map +1 -0
  409. package/dist/objects/persistence/migration-runner.js +562 -0
  410. package/dist/objects/persistence/migration-runner.js.map +1 -0
  411. package/dist/objects/persistence/replication-manager.js +501 -0
  412. package/dist/objects/persistence/replication-manager.js.map +1 -0
  413. package/dist/objects/persistence/tiered-storage-manager.js +595 -0
  414. package/dist/objects/persistence/tiered-storage-manager.js.map +1 -0
  415. package/dist/objects/persistence/types.js +14 -0
  416. package/dist/objects/persistence/types.js.map +1 -0
  417. package/dist/objects/persistence/wal-manager.js +653 -0
  418. package/dist/objects/persistence/wal-manager.js.map +1 -0
  419. package/dist/objects/presets/index.js +20 -0
  420. package/dist/objects/presets/index.js.map +1 -0
  421. package/dist/objects/presets/primitives.js +188 -0
  422. package/dist/objects/presets/primitives.js.map +1 -0
  423. package/dist/objects/primitives/alarm-adapter.js +141 -0
  424. package/dist/objects/primitives/alarm-adapter.js.map +1 -0
  425. package/dist/objects/primitives/index.js +337 -0
  426. package/dist/objects/primitives/index.js.map +1 -0
  427. package/dist/objects/primitives/storage-adapter.js +182 -0
  428. package/dist/objects/primitives/storage-adapter.js.map +1 -0
  429. package/dist/objects/primitives/with-primitives.js +102 -0
  430. package/dist/objects/primitives/with-primitives.js.map +1 -0
  431. package/dist/objects/services/StoreManager.js +227 -0
  432. package/dist/objects/services/StoreManager.js.map +1 -0
  433. package/dist/objects/services/index.js +13 -0
  434. package/dist/objects/services/index.js.map +1 -0
  435. package/dist/objects/transport/auth-layer.js +1451 -0
  436. package/dist/objects/transport/auth-layer.js.map +1 -0
  437. package/dist/objects/transport/capnweb-target.js +355 -0
  438. package/dist/objects/transport/capnweb-target.js.map +1 -0
  439. package/dist/objects/transport/chain.js +441 -0
  440. package/dist/objects/transport/chain.js.map +1 -0
  441. package/dist/objects/transport/handler.js +58 -0
  442. package/dist/objects/transport/handler.js.map +1 -0
  443. package/dist/objects/transport/index.js +53 -0
  444. package/dist/objects/transport/index.js.map +1 -0
  445. package/dist/objects/transport/mcp-server.js +690 -0
  446. package/dist/objects/transport/mcp-server.js.map +1 -0
  447. package/dist/objects/transport/rest-autowire.js +1507 -0
  448. package/dist/objects/transport/rest-autowire.js.map +1 -0
  449. package/dist/objects/transport/rest-router.js +440 -0
  450. package/dist/objects/transport/rest-router.js.map +1 -0
  451. package/dist/objects/transport/rpc-server.js +1536 -0
  452. package/dist/objects/transport/rpc-server.js.map +1 -0
  453. package/dist/objects/transport/shared.js +575 -0
  454. package/dist/objects/transport/shared.js.map +1 -0
  455. package/dist/objects/transport/sync-engine.js +291 -0
  456. package/dist/objects/transport/sync-engine.js.map +1 -0
  457. package/dist/objects/transport/types.js +8 -0
  458. package/dist/objects/transport/types.js.map +1 -0
  459. package/dist/primitives/bashx/src/ast/analyze.js +1472 -0
  460. package/dist/primitives/bashx/src/ast/analyze.js.map +1 -0
  461. package/dist/primitives/bashx/src/ast/parser.js +1488 -0
  462. package/dist/primitives/bashx/src/ast/parser.js.map +1 -0
  463. package/dist/primitives/bashx/src/do/commands/crypto.js +1954 -0
  464. package/dist/primitives/bashx/src/do/commands/crypto.js.map +1 -0
  465. package/dist/primitives/bashx/src/do/commands/data-processing.js +1812 -0
  466. package/dist/primitives/bashx/src/do/commands/data-processing.js.map +1 -0
  467. package/dist/primitives/bashx/src/do/commands/extended-utils.js +804 -0
  468. package/dist/primitives/bashx/src/do/commands/extended-utils.js.map +1 -0
  469. package/dist/primitives/bashx/src/do/commands/math-control.js +1122 -0
  470. package/dist/primitives/bashx/src/do/commands/math-control.js.map +1 -0
  471. package/dist/primitives/bashx/src/do/commands/posix-utils.js +1015 -0
  472. package/dist/primitives/bashx/src/do/commands/posix-utils.js.map +1 -0
  473. package/dist/primitives/bashx/src/do/commands/system-utils.js +687 -0
  474. package/dist/primitives/bashx/src/do/commands/system-utils.js.map +1 -0
  475. package/dist/primitives/bashx/src/do/commands/test-command.js +523 -0
  476. package/dist/primitives/bashx/src/do/commands/test-command.js.map +1 -0
  477. package/dist/primitives/bashx/src/do/commands/text-processing.js +1550 -0
  478. package/dist/primitives/bashx/src/do/commands/text-processing.js.map +1 -0
  479. package/dist/primitives/bashx/src/do/container-executor.js +429 -0
  480. package/dist/primitives/bashx/src/do/container-executor.js.map +1 -0
  481. package/dist/primitives/bashx/src/do/index.js +668 -0
  482. package/dist/primitives/bashx/src/do/index.js.map +1 -0
  483. package/dist/primitives/bashx/src/do/tiered-executor.js +2647 -0
  484. package/dist/primitives/bashx/src/do/tiered-executor.js.map +1 -0
  485. package/dist/primitives/bashx/src/do/worker.js +352 -0
  486. package/dist/primitives/bashx/src/do/worker.js.map +1 -0
  487. package/dist/primitives/bashx/src/types.js +10 -0
  488. package/dist/primitives/bashx/src/types.js.map +1 -0
  489. package/dist/primitives/fsx/core/backend.js +480 -0
  490. package/dist/primitives/fsx/core/backend.js.map +1 -0
  491. package/dist/primitives/fsx/core/constants.js +140 -0
  492. package/dist/primitives/fsx/core/constants.js.map +1 -0
  493. package/dist/primitives/fsx/core/fsx.js +1184 -0
  494. package/dist/primitives/fsx/core/fsx.js.map +1 -0
  495. package/dist/primitives/fsx/core/glob/glob.js +438 -0
  496. package/dist/primitives/fsx/core/glob/glob.js.map +1 -0
  497. package/dist/primitives/fsx/core/glob/index.js +8 -0
  498. package/dist/primitives/fsx/core/glob/index.js.map +1 -0
  499. package/dist/primitives/fsx/core/glob/match.js +392 -0
  500. package/dist/primitives/fsx/core/glob/match.js.map +1 -0
  501. package/dist/primitives/fsx/core/types.js +307 -0
  502. package/dist/primitives/fsx/core/types.js.map +1 -0
  503. package/dist/sandbox/index.js +258 -0
  504. package/dist/sandbox/index.js.map +1 -0
  505. package/dist/sdk/capnweb-compat.js +42 -0
  506. package/dist/sdk/capnweb-compat.js.map +1 -0
  507. package/dist/sdk/client.js +20 -0
  508. package/dist/sdk/client.js.map +1 -0
  509. package/dist/sdk/index.js +17 -0
  510. package/dist/sdk/index.js.map +1 -0
  511. package/dist/snippets/artifacts-config.js +241 -0
  512. package/dist/snippets/artifacts-config.js.map +1 -0
  513. package/dist/snippets/artifacts-ingest.js +832 -0
  514. package/dist/snippets/artifacts-ingest.js.map +1 -0
  515. package/dist/snippets/artifacts-serve.js +1035 -0
  516. package/dist/snippets/artifacts-serve.js.map +1 -0
  517. package/dist/snippets/artifacts-types.js +161 -0
  518. package/dist/snippets/artifacts-types.js.map +1 -0
  519. package/dist/snippets/cache-probe.js +376 -0
  520. package/dist/snippets/cache-probe.js.map +1 -0
  521. package/dist/snippets/cache.js +10 -0
  522. package/dist/snippets/cache.js.map +1 -0
  523. package/dist/snippets/events.js +469 -0
  524. package/dist/snippets/events.js.map +1 -0
  525. package/dist/snippets/index.js +7 -0
  526. package/dist/snippets/index.js.map +1 -0
  527. package/dist/snippets/proxy.js +495 -0
  528. package/dist/snippets/proxy.js.map +1 -0
  529. package/dist/snippets/search.js +1759 -0
  530. package/dist/snippets/search.js.map +1 -0
  531. package/dist/streams/index.js +30 -0
  532. package/dist/streams/index.js.map +1 -0
  533. package/dist/streams/observability.js +68 -0
  534. package/dist/streams/observability.js.map +1 -0
  535. package/dist/types/AI.js +92 -0
  536. package/dist/types/AI.js.map +1 -0
  537. package/dist/types/AIFunction.js +171 -0
  538. package/dist/types/AIFunction.js.map +1 -0
  539. package/dist/types/BrowseVerb.js +89 -0
  540. package/dist/types/BrowseVerb.js.map +1 -0
  541. package/dist/types/Browser.js +31 -0
  542. package/dist/types/Browser.js.map +1 -0
  543. package/dist/types/Chaos.js +15 -0
  544. package/dist/types/Chaos.js.map +1 -0
  545. package/dist/types/CloudflareBindings.js +109 -0
  546. package/dist/types/CloudflareBindings.js.map +1 -0
  547. package/dist/types/Collection.js +50 -0
  548. package/dist/types/Collection.js.map +1 -0
  549. package/dist/types/DO.js +2 -0
  550. package/dist/types/DO.js.map +1 -0
  551. package/dist/types/DOLocation.js +63 -0
  552. package/dist/types/DOLocation.js.map +1 -0
  553. package/dist/types/EventHandler.js +57 -0
  554. package/dist/types/EventHandler.js.map +1 -0
  555. package/dist/types/Experiment.js +33 -0
  556. package/dist/types/Experiment.js.map +1 -0
  557. package/dist/types/Flag.js +57 -0
  558. package/dist/types/Flag.js.map +1 -0
  559. package/dist/types/Lifecycle.js +13 -0
  560. package/dist/types/Lifecycle.js.map +1 -0
  561. package/dist/types/Location.js +169 -0
  562. package/dist/types/Location.js.map +1 -0
  563. package/dist/types/Noun.js +66 -0
  564. package/dist/types/Noun.js.map +1 -0
  565. package/dist/types/SessionEvent.js +194 -0
  566. package/dist/types/SessionEvent.js.map +1 -0
  567. package/dist/types/Thing.js +55 -0
  568. package/dist/types/Thing.js.map +1 -0
  569. package/dist/types/ThingDO.js +153 -0
  570. package/dist/types/ThingDO.js.map +1 -0
  571. package/dist/types/Things.js +2 -0
  572. package/dist/types/Things.js.map +1 -0
  573. package/dist/types/Verb.js +119 -0
  574. package/dist/types/Verb.js.map +1 -0
  575. package/dist/types/WorkflowContext.js +70 -0
  576. package/dist/types/WorkflowContext.js.map +1 -0
  577. package/dist/types/analytics-api.js +13 -0
  578. package/dist/types/analytics-api.js.map +1 -0
  579. package/dist/types/capabilities.js +135 -0
  580. package/dist/types/capabilities.js.map +1 -0
  581. package/dist/types/drizzle.js +12 -0
  582. package/dist/types/drizzle.js.map +1 -0
  583. package/dist/types/event.js +201 -0
  584. package/dist/types/event.js.map +1 -0
  585. package/dist/types/fn.js +12 -0
  586. package/dist/types/fn.js.map +1 -0
  587. package/dist/types/iceberg.js +48 -0
  588. package/dist/types/iceberg.js.map +1 -0
  589. package/dist/types/ids.js +170 -0
  590. package/dist/types/ids.js.map +1 -0
  591. package/dist/types/index.js +41 -0
  592. package/dist/types/index.js.map +1 -0
  593. package/dist/types/introspect.js +54 -0
  594. package/dist/types/introspect.js.map +1 -0
  595. package/dist/types/observability.js +124 -0
  596. package/dist/types/observability.js.map +1 -0
  597. package/dist/types/sync-protocol.js +175 -0
  598. package/dist/types/sync-protocol.js.map +1 -0
  599. package/dist/types/vector.js +13 -0
  600. package/dist/types/vector.js.map +1 -0
  601. package/dist/workflows/ScheduleManager.js +473 -0
  602. package/dist/workflows/ScheduleManager.js.map +1 -0
  603. package/dist/workflows/StepDOBridge.js +149 -0
  604. package/dist/workflows/StepDOBridge.js.map +1 -0
  605. package/dist/workflows/StepResultStorage.js +232 -0
  606. package/dist/workflows/StepResultStorage.js.map +1 -0
  607. package/dist/workflows/WaitForEventManager.js +461 -0
  608. package/dist/workflows/WaitForEventManager.js.map +1 -0
  609. package/dist/workflows/analyzer.js +332 -0
  610. package/dist/workflows/analyzer.js.map +1 -0
  611. package/dist/workflows/compat/activity-router.js +484 -0
  612. package/dist/workflows/compat/activity-router.js.map +1 -0
  613. package/dist/workflows/compat/backends/cloudflare-workflows.js +431 -0
  614. package/dist/workflows/compat/backends/cloudflare-workflows.js.map +1 -0
  615. package/dist/workflows/compat/backends/index.js +14 -0
  616. package/dist/workflows/compat/backends/index.js.map +1 -0
  617. package/dist/workflows/compat/errors/index.js +375 -0
  618. package/dist/workflows/compat/errors/index.js.map +1 -0
  619. package/dist/workflows/compat/index.js +79 -0
  620. package/dist/workflows/compat/index.js.map +1 -0
  621. package/dist/workflows/compat/inngest/index.js +989 -0
  622. package/dist/workflows/compat/inngest/index.js.map +1 -0
  623. package/dist/workflows/compat/qstash/index.js +1263 -0
  624. package/dist/workflows/compat/qstash/index.js.map +1 -0
  625. package/dist/workflows/compat/temporal/activities.js +739 -0
  626. package/dist/workflows/compat/temporal/activities.js.map +1 -0
  627. package/dist/workflows/compat/temporal/child-workflows.js +154 -0
  628. package/dist/workflows/compat/temporal/child-workflows.js.map +1 -0
  629. package/dist/workflows/compat/temporal/client.js +381 -0
  630. package/dist/workflows/compat/temporal/client.js.map +1 -0
  631. package/dist/workflows/compat/temporal/context.js +309 -0
  632. package/dist/workflows/compat/temporal/context.js.map +1 -0
  633. package/dist/workflows/compat/temporal/determinism.js +216 -0
  634. package/dist/workflows/compat/temporal/determinism.js.map +1 -0
  635. package/dist/workflows/compat/temporal/errors.js +128 -0
  636. package/dist/workflows/compat/temporal/errors.js.map +1 -0
  637. package/dist/workflows/compat/temporal/index.js +2464 -0
  638. package/dist/workflows/compat/temporal/index.js.map +1 -0
  639. package/dist/workflows/compat/temporal/saga.js +504 -0
  640. package/dist/workflows/compat/temporal/saga.js.map +1 -0
  641. package/dist/workflows/compat/temporal/signals.js +364 -0
  642. package/dist/workflows/compat/temporal/signals.js.map +1 -0
  643. package/dist/workflows/compat/temporal/storage.js +271 -0
  644. package/dist/workflows/compat/temporal/storage.js.map +1 -0
  645. package/dist/workflows/compat/temporal/timers.js +347 -0
  646. package/dist/workflows/compat/temporal/timers.js.map +1 -0
  647. package/dist/workflows/compat/temporal/types.js +7 -0
  648. package/dist/workflows/compat/temporal/types.js.map +1 -0
  649. package/dist/workflows/compat/temporal/unified-primitives.js +339 -0
  650. package/dist/workflows/compat/temporal/unified-primitives.js.map +1 -0
  651. package/dist/workflows/compat/trigger/index.js +468 -0
  652. package/dist/workflows/compat/trigger/index.js.map +1 -0
  653. package/dist/workflows/compat/utils/index.js +69 -0
  654. package/dist/workflows/compat/utils/index.js.map +1 -0
  655. package/dist/workflows/context/correlation-capability.js +266 -0
  656. package/dist/workflows/context/correlation-capability.js.map +1 -0
  657. package/dist/workflows/context/correlation.js +484 -0
  658. package/dist/workflows/context/correlation.js.map +1 -0
  659. package/dist/workflows/context/experiment.js +289 -0
  660. package/dist/workflows/context/experiment.js.map +1 -0
  661. package/dist/workflows/context/flag.js +244 -0
  662. package/dist/workflows/context/flag.js.map +1 -0
  663. package/dist/workflows/context/foundation.js +648 -0
  664. package/dist/workflows/context/foundation.js.map +1 -0
  665. package/dist/workflows/context/human-base.js +106 -0
  666. package/dist/workflows/context/human-base.js.map +1 -0
  667. package/dist/workflows/context/human.js +368 -0
  668. package/dist/workflows/context/human.js.map +1 -0
  669. package/dist/workflows/context/measure.js +354 -0
  670. package/dist/workflows/context/measure.js.map +1 -0
  671. package/dist/workflows/context/rate-limit.js +358 -0
  672. package/dist/workflows/context/rate-limit.js.map +1 -0
  673. package/dist/workflows/context/user.js +117 -0
  674. package/dist/workflows/context/user.js.map +1 -0
  675. package/dist/workflows/context/vault.js +360 -0
  676. package/dist/workflows/context/vault.js.map +1 -0
  677. package/dist/workflows/data/entity-events/entity-events.js +489 -0
  678. package/dist/workflows/data/entity-events/entity-events.js.map +1 -0
  679. package/dist/workflows/data/experiment/index.js +599 -0
  680. package/dist/workflows/data/experiment/index.js.map +1 -0
  681. package/dist/workflows/data/goal/context.js +558 -0
  682. package/dist/workflows/data/goal/context.js.map +1 -0
  683. package/dist/workflows/data/goal/index.js +32 -0
  684. package/dist/workflows/data/goal/index.js.map +1 -0
  685. package/dist/workflows/data/measure/index.js +840 -0
  686. package/dist/workflows/data/measure/index.js.map +1 -0
  687. package/dist/workflows/data/stream/index.js +1215 -0
  688. package/dist/workflows/data/stream/index.js.map +1 -0
  689. package/dist/workflows/data/track/context.js +883 -0
  690. package/dist/workflows/data/track/context.js.map +1 -0
  691. package/dist/workflows/data/track/index.js +15 -0
  692. package/dist/workflows/data/track/index.js.map +1 -0
  693. package/dist/workflows/data/view/context.js +864 -0
  694. package/dist/workflows/data/view/context.js.map +1 -0
  695. package/dist/workflows/domain.js +93 -0
  696. package/dist/workflows/domain.js.map +1 -0
  697. package/dist/workflows/flag.js +176 -0
  698. package/dist/workflows/flag.js.map +1 -0
  699. package/dist/workflows/flags.js +217 -0
  700. package/dist/workflows/flags.js.map +1 -0
  701. package/dist/workflows/hash.js +209 -0
  702. package/dist/workflows/hash.js.map +1 -0
  703. package/dist/workflows/index.js +50 -0
  704. package/dist/workflows/index.js.map +1 -0
  705. package/dist/workflows/on.js +378 -0
  706. package/dist/workflows/on.js.map +1 -0
  707. package/dist/workflows/pipeline-promise.js +481 -0
  708. package/dist/workflows/pipeline-promise.js.map +1 -0
  709. package/dist/workflows/pipeline-types.js +20 -0
  710. package/dist/workflows/pipeline-types.js.map +1 -0
  711. package/dist/workflows/proxy.js +76 -0
  712. package/dist/workflows/proxy.js.map +1 -0
  713. package/dist/workflows/runtime.js +310 -0
  714. package/dist/workflows/runtime.js.map +1 -0
  715. package/dist/workflows/schedule-builder.js +327 -0
  716. package/dist/workflows/schedule-builder.js.map +1 -0
  717. package/dist/workflows/visibility/index.js +148 -0
  718. package/dist/workflows/visibility/index.js.map +1 -0
  719. package/dist/workflows/visibility/query-parser.js +150 -0
  720. package/dist/workflows/visibility/query-parser.js.map +1 -0
  721. package/dist/workflows/visibility/store.js +223 -0
  722. package/dist/workflows/visibility/store.js.map +1 -0
  723. package/dist/workflows/visibility/types.js +30 -0
  724. package/dist/workflows/visibility/types.js.map +1 -0
  725. package/dist/workflows/workflow.js +53 -0
  726. package/dist/workflows/workflow.js.map +1 -0
  727. package/package.json +279 -46
@@ -0,0 +1,1184 @@
1
+ /**
2
+ * FSx - Main filesystem class
3
+ *
4
+ * Provides POSIX-like filesystem operations backed by a pluggable FsBackend.
5
+ * This is the primary interface for interacting with the virtual filesystem.
6
+ *
7
+ * The core FSx class is runtime-agnostic and has zero Cloudflare dependencies.
8
+ * For Durable Object integration, use the DOBackend from fsx/do.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import { FSx, MemoryBackend } from '@dotdo/fsx'
13
+ *
14
+ * // Use with in-memory backend for testing
15
+ * const backend = new MemoryBackend()
16
+ * const fsx = new FSx(backend)
17
+ *
18
+ * // Write and read files
19
+ * await fsx.writeFile('/hello.txt', 'Hello, World!')
20
+ * const content = await fsx.readFile('/hello.txt')
21
+ *
22
+ * // Directory operations
23
+ * await fsx.mkdir('/mydir', { recursive: true })
24
+ * const files = await fsx.readdir('/mydir')
25
+ *
26
+ * // Check file stats
27
+ * const stats = await fsx.stat('/hello.txt')
28
+ * console.log(stats.size, stats.isFile())
29
+ * ```
30
+ *
31
+ * @module
32
+ */
33
+ // Note: constants is referenced in JSDoc examples only
34
+ export { constants } from './constants.js';
35
+ /**
36
+ * Manages file watchers for a single FSx instance.
37
+ *
38
+ * Optimized for handling many concurrent watchers by using:
39
+ * - Path prefix indexing for O(log n) lookup of potentially matching watchers
40
+ * - Batch notification to avoid callback storms
41
+ * - Proper cancellation support via AbortController
42
+ *
43
+ * Since FSx runs in a Durable Object environment without native fs.watch,
44
+ * this class implements watching by hooking into FSx operations directly.
45
+ * When a file operation occurs, the WatchManager emits events to all
46
+ * registered watchers that match the affected path.
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * const manager = new WatchManager()
51
+ * const entry = manager.addWatcher('/home/user', true, (event, filename) => {
52
+ * console.log(`${event}: ${filename}`)
53
+ * })
54
+ *
55
+ * // Emit an event
56
+ * manager.emit('change', '/home/user/file.txt')
57
+ *
58
+ * // Later, remove the watcher
59
+ * manager.removeWatcher(entry)
60
+ * ```
61
+ */
62
+ class WatchManager {
63
+ /** Counter for generating unique watcher IDs */
64
+ nextId = 0;
65
+ /** All registered watchers indexed by ID for fast removal */
66
+ watchersById = new Map();
67
+ /**
68
+ * Index of watchers by their normalized path.
69
+ * Multiple watchers can watch the same path.
70
+ */
71
+ watchersByPath = new Map();
72
+ // Reserved for future optimization - sorted watched paths for efficient prefix matching
73
+ // @ts-expect-error Reserved for future use
74
+ _sortedPaths = [];
75
+ // @ts-expect-error Reserved for future use
76
+ _pathsNeedSort = false;
77
+ /**
78
+ * Register a new file system watcher.
79
+ *
80
+ * @param path - The path to watch (file or directory)
81
+ * @param recursive - Whether to watch subdirectories recursively
82
+ * @param listener - Callback function to invoke on events
83
+ * @returns The watch entry for later removal
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * const entry = manager.addWatcher('/home/user', true, (event, filename) => {
88
+ * console.log(`${event}: ${filename}`)
89
+ * })
90
+ * ```
91
+ */
92
+ addWatcher(path, recursive, listener) {
93
+ const normalizedPath = this.normalizePath(path);
94
+ const entry = {
95
+ id: this.nextId++,
96
+ path: normalizedPath,
97
+ recursive,
98
+ listener,
99
+ closed: false,
100
+ abortController: new AbortController(),
101
+ };
102
+ // Add to ID index
103
+ this.watchersById.set(entry.id, entry);
104
+ // Add to path index
105
+ let pathWatchers = this.watchersByPath.get(normalizedPath);
106
+ if (!pathWatchers) {
107
+ pathWatchers = new Set();
108
+ this.watchersByPath.set(normalizedPath, pathWatchers);
109
+ this._pathsNeedSort = true;
110
+ }
111
+ pathWatchers.add(entry);
112
+ return entry;
113
+ }
114
+ /**
115
+ * Remove a watcher and clean up its resources.
116
+ *
117
+ * @param entry - The watch entry to remove
118
+ */
119
+ removeWatcher(entry) {
120
+ entry.closed = true;
121
+ entry.abortController.abort();
122
+ // Remove from ID index
123
+ this.watchersById.delete(entry.id);
124
+ // Remove from path index
125
+ const pathWatchers = this.watchersByPath.get(entry.path);
126
+ if (pathWatchers) {
127
+ pathWatchers.delete(entry);
128
+ if (pathWatchers.size === 0) {
129
+ this.watchersByPath.delete(entry.path);
130
+ this._pathsNeedSort = true;
131
+ }
132
+ }
133
+ }
134
+ /**
135
+ * Get the AbortSignal for a watcher, useful for cancellation.
136
+ *
137
+ * @param entry - The watch entry
138
+ * @returns The AbortSignal that will be triggered when the watcher is closed
139
+ */
140
+ getAbortSignal(entry) {
141
+ return entry.abortController.signal;
142
+ }
143
+ /**
144
+ * Get the total number of active watchers.
145
+ *
146
+ * @returns Number of registered watchers
147
+ */
148
+ get watcherCount() {
149
+ return this.watchersById.size;
150
+ }
151
+ /**
152
+ * Emit a file system event to all matching watchers.
153
+ *
154
+ * Uses optimized path matching to minimize iteration:
155
+ * 1. Direct path watchers (exact match)
156
+ * 2. Parent directory watchers (non-recursive, direct children only)
157
+ * 3. Ancestor directory watchers (recursive)
158
+ *
159
+ * @param eventType - 'change' for content modifications, 'rename' for create/delete/rename
160
+ * @param affectedPath - The full normalized path that was affected
161
+ *
162
+ * @example
163
+ * ```typescript
164
+ * // Emit a change event for a modified file
165
+ * manager.emit('change', '/home/user/file.txt')
166
+ *
167
+ * // Emit a rename event for a created file
168
+ * manager.emit('rename', '/home/user/new-file.txt')
169
+ * ```
170
+ */
171
+ emit(eventType, affectedPath) {
172
+ const normalizedAffected = this.normalizePath(affectedPath);
173
+ const matchingWatchers = [];
174
+ // 1. Check for exact path watchers (watching this specific file/dir)
175
+ const exactWatchers = this.watchersByPath.get(normalizedAffected);
176
+ if (exactWatchers) {
177
+ for (const watcher of exactWatchers) {
178
+ if (!watcher.closed) {
179
+ const filename = this.getBasename(normalizedAffected);
180
+ matchingWatchers.push({ watcher, filename });
181
+ }
182
+ }
183
+ }
184
+ // 2. Check for parent directory watchers
185
+ let currentPath = this.getParentPath(normalizedAffected);
186
+ if (currentPath !== normalizedAffected) {
187
+ // Direct parent watchers (both recursive and non-recursive)
188
+ const parentWatchers = this.watchersByPath.get(currentPath);
189
+ if (parentWatchers) {
190
+ for (const watcher of parentWatchers) {
191
+ if (!watcher.closed) {
192
+ const filename = this.getBasename(normalizedAffected);
193
+ matchingWatchers.push({ watcher, filename });
194
+ }
195
+ }
196
+ }
197
+ // 3. Check for ancestor directory watchers (recursive only)
198
+ let ancestorPath = this.getParentPath(currentPath);
199
+ while (ancestorPath !== currentPath) {
200
+ const ancestorWatchers = this.watchersByPath.get(ancestorPath);
201
+ if (ancestorWatchers) {
202
+ for (const watcher of ancestorWatchers) {
203
+ if (!watcher.closed && watcher.recursive) {
204
+ const filename = this.getRelativePath(ancestorPath, normalizedAffected);
205
+ matchingWatchers.push({ watcher, filename });
206
+ }
207
+ }
208
+ }
209
+ currentPath = ancestorPath;
210
+ ancestorPath = this.getParentPath(ancestorPath);
211
+ }
212
+ // Check root watchers if we're not at root
213
+ if (currentPath !== '/') {
214
+ const rootWatchers = this.watchersByPath.get('/');
215
+ if (rootWatchers) {
216
+ for (const watcher of rootWatchers) {
217
+ if (!watcher.closed && watcher.recursive) {
218
+ const filename = normalizedAffected.slice(1); // Remove leading /
219
+ matchingWatchers.push({ watcher, filename });
220
+ }
221
+ }
222
+ }
223
+ }
224
+ }
225
+ // Fire all callbacks asynchronously using queueMicrotask for batching
226
+ for (const { watcher, filename } of matchingWatchers) {
227
+ queueMicrotask(() => {
228
+ if (!watcher.closed) {
229
+ try {
230
+ watcher.listener(eventType, filename);
231
+ }
232
+ catch {
233
+ // Swallow listener errors to prevent breaking other watchers
234
+ }
235
+ }
236
+ });
237
+ }
238
+ }
239
+ /**
240
+ * Normalize a path by removing trailing slashes (except for root).
241
+ * @param path - Path to normalize
242
+ * @returns Normalized path
243
+ */
244
+ normalizePath(path) {
245
+ if (path === '/' || path === '')
246
+ return '/';
247
+ return path.endsWith('/') ? path.slice(0, -1) : path;
248
+ }
249
+ /**
250
+ * Get the parent directory path.
251
+ * @param path - Path to get parent of
252
+ * @returns Parent path, or the same path if at root
253
+ */
254
+ getParentPath(path) {
255
+ if (path === '/')
256
+ return '/';
257
+ const lastSlash = path.lastIndexOf('/');
258
+ if (lastSlash <= 0)
259
+ return '/';
260
+ return path.slice(0, lastSlash);
261
+ }
262
+ /**
263
+ * Get the basename (final component) of a path.
264
+ * @param path - Path to get basename of
265
+ * @returns Basename
266
+ */
267
+ getBasename(path) {
268
+ const lastSlash = path.lastIndexOf('/');
269
+ return lastSlash >= 0 ? path.slice(lastSlash + 1) : path;
270
+ }
271
+ /**
272
+ * Get the relative path from a base to a target.
273
+ * @param basePath - Base path
274
+ * @param targetPath - Target path
275
+ * @returns Relative path from base to target
276
+ */
277
+ getRelativePath(basePath, targetPath) {
278
+ const normalizedBase = this.normalizePath(basePath);
279
+ const normalizedTarget = this.normalizePath(targetPath);
280
+ if (normalizedBase === '/') {
281
+ return normalizedTarget.slice(1);
282
+ }
283
+ if (normalizedTarget.startsWith(normalizedBase + '/')) {
284
+ return normalizedTarget.slice(normalizedBase.length + 1);
285
+ }
286
+ return this.getBasename(normalizedTarget);
287
+ }
288
+ }
289
+ const DEFAULT_OPTIONS = {
290
+ tiers: {
291
+ hotMaxSize: 1024 * 1024, // 1MB
292
+ warmEnabled: true,
293
+ coldEnabled: false,
294
+ },
295
+ defaultMode: 0o644,
296
+ defaultDirMode: 0o755,
297
+ tmpMaxAge: 24 * 60 * 60 * 1000, // 24 hours
298
+ maxFileSize: 100 * 1024 * 1024, // 100MB
299
+ maxPathLength: 4096,
300
+ uid: 0,
301
+ gid: 0,
302
+ };
303
+ /**
304
+ * FSx - Virtual filesystem with pluggable backend
305
+ *
306
+ * The core FSx class is runtime-agnostic and works with any FsBackend implementation.
307
+ * For Cloudflare Durable Objects, use the DOBackend from fsx/do.
308
+ */
309
+ export class FSx {
310
+ backend;
311
+ options;
312
+ watchManager = new WatchManager();
313
+ constructor(backend, options = {}) {
314
+ this.backend = backend;
315
+ this.options = { ...DEFAULT_OPTIONS, ...options };
316
+ }
317
+ /**
318
+ * Normalize a path
319
+ */
320
+ normalizePath(path) {
321
+ // Remove trailing slashes (except root)
322
+ if (path !== '/' && path.endsWith('/')) {
323
+ path = path.slice(0, -1);
324
+ }
325
+ // Ensure starts with /
326
+ if (!path.startsWith('/')) {
327
+ path = '/' + path;
328
+ }
329
+ // Resolve . and ..
330
+ const parts = path.split('/').filter(Boolean);
331
+ const resolved = [];
332
+ for (const part of parts) {
333
+ if (part === '.')
334
+ continue;
335
+ if (part === '..') {
336
+ resolved.pop();
337
+ }
338
+ else {
339
+ resolved.push(part);
340
+ }
341
+ }
342
+ return '/' + resolved.join('/');
343
+ }
344
+ // ==================== File Operations ====================
345
+ /**
346
+ * Read a file's contents
347
+ *
348
+ * Reads the entire contents of a file. By default, returns a UTF-8 decoded string.
349
+ * Use the encoding parameter to control the output format.
350
+ *
351
+ * @param path - Path to the file to read
352
+ * @param encoding - Output encoding: 'utf-8'/'utf8' (default), 'base64', or undefined for raw bytes
353
+ * @returns File contents as a string or Uint8Array depending on encoding
354
+ * @throws {ENOENT} If the file does not exist
355
+ * @throws {EISDIR} If the path is a directory
356
+ *
357
+ * @example
358
+ * ```typescript
359
+ * // Read as UTF-8 string (default)
360
+ * const text = await fsx.readFile('/hello.txt')
361
+ *
362
+ * // Read as raw bytes
363
+ * const bytes = await fsx.readFile('/image.png', undefined)
364
+ *
365
+ * // Read as base64
366
+ * const base64 = await fsx.readFile('/image.png', 'base64')
367
+ * ```
368
+ */
369
+ async readFile(path, encoding) {
370
+ path = this.normalizePath(path);
371
+ const bytes = await this.backend.readFile(path);
372
+ // If utf-8 encoding requested (or default), decode bytes to string
373
+ if (!encoding || encoding === 'utf-8' || encoding === 'utf8') {
374
+ return new TextDecoder().decode(bytes);
375
+ }
376
+ // If base64 encoding requested, encode bytes to base64
377
+ if (encoding === 'base64') {
378
+ let binary = '';
379
+ for (const byte of bytes) {
380
+ binary += String.fromCharCode(byte);
381
+ }
382
+ return btoa(binary);
383
+ }
384
+ // For other encodings or no encoding, return bytes
385
+ return bytes;
386
+ }
387
+ /**
388
+ * Write data to a file
389
+ *
390
+ * Writes data to a file, replacing the file if it already exists.
391
+ * Creates any necessary parent directories.
392
+ *
393
+ * @param path - Path to the file to write
394
+ * @param data - Content to write (string or bytes)
395
+ * @param options - Write options
396
+ * @param options.mode - File permissions (default: 0o644)
397
+ * @param options.flag - File system flag: 'w' (write/create), 'a' (append), 'wx' (exclusive create)
398
+ * @throws {EISDIR} If the path is a directory
399
+ *
400
+ * @example
401
+ * ```typescript
402
+ * // Write a string
403
+ * await fsx.writeFile('/hello.txt', 'Hello, World!')
404
+ *
405
+ * // Write binary data
406
+ * await fsx.writeFile('/data.bin', new Uint8Array([1, 2, 3]))
407
+ *
408
+ * // Write with specific permissions
409
+ * await fsx.writeFile('/script.sh', '#!/bin/bash', { mode: 0o755 })
410
+ * ```
411
+ */
412
+ async writeFile(path, data, options) {
413
+ path = this.normalizePath(path);
414
+ // Check if file exists before writing (to determine event type)
415
+ const fileExisted = await this.backend.exists(path);
416
+ // Convert string to bytes
417
+ const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : data;
418
+ await this.backend.writeFile(path, bytes, {
419
+ mode: options?.mode ?? this.options.defaultMode,
420
+ flag: options?.flag,
421
+ });
422
+ // Emit watch event - 'rename' for new file, 'change' for existing
423
+ this.watchManager.emit(fileExisted ? 'change' : 'rename', path);
424
+ }
425
+ /**
426
+ * Append data to a file
427
+ *
428
+ * Appends data to the end of a file. Creates the file if it doesn't exist.
429
+ *
430
+ * @param path - Path to the file
431
+ * @param data - Content to append
432
+ * @throws {EISDIR} If the path is a directory
433
+ *
434
+ * @example
435
+ * ```typescript
436
+ * await fsx.appendFile('/log.txt', 'New log entry\n')
437
+ * ```
438
+ */
439
+ async appendFile(path, data) {
440
+ return this.writeFile(path, data, { flag: 'a' });
441
+ }
442
+ /**
443
+ * Delete a file
444
+ *
445
+ * Removes a file from the filesystem. Does not work on directories.
446
+ *
447
+ * @param path - Path to the file to delete
448
+ * @throws {ENOENT} If the file does not exist
449
+ * @throws {EISDIR} If the path is a directory (use rmdir or rm instead)
450
+ *
451
+ * @example
452
+ * ```typescript
453
+ * await fsx.unlink('/old-file.txt')
454
+ * ```
455
+ */
456
+ async unlink(path) {
457
+ path = this.normalizePath(path);
458
+ await this.backend.unlink(path);
459
+ // Emit watch event - 'rename' for file deletion
460
+ this.watchManager.emit('rename', path);
461
+ }
462
+ /**
463
+ * Rename or move a file or directory
464
+ *
465
+ * Atomically renames or moves a file/directory from oldPath to newPath.
466
+ * Can be used to move files between directories.
467
+ *
468
+ * @param oldPath - Current path
469
+ * @param newPath - New path
470
+ * @throws {ENOENT} If oldPath does not exist
471
+ * @throws {EEXIST} If newPath already exists (for some filesystem configurations)
472
+ *
473
+ * @example
474
+ * ```typescript
475
+ * // Rename a file
476
+ * await fsx.rename('/old-name.txt', '/new-name.txt')
477
+ *
478
+ * // Move to another directory
479
+ * await fsx.rename('/file.txt', '/archive/file.txt')
480
+ * ```
481
+ */
482
+ async rename(oldPath, newPath) {
483
+ oldPath = this.normalizePath(oldPath);
484
+ newPath = this.normalizePath(newPath);
485
+ await this.backend.rename(oldPath, newPath);
486
+ // Emit watch events - 'rename' for both old and new paths
487
+ this.watchManager.emit('rename', oldPath);
488
+ this.watchManager.emit('rename', newPath);
489
+ }
490
+ /**
491
+ * Copy a file
492
+ *
493
+ * Creates a copy of a file at the destination path.
494
+ *
495
+ * @param src - Source file path
496
+ * @param dest - Destination file path
497
+ * @param flags - Copy flags (e.g., constants.COPYFILE_EXCL to fail if dest exists)
498
+ * @throws {ENOENT} If the source file does not exist
499
+ * @throws {EEXIST} If dest exists and COPYFILE_EXCL flag is set
500
+ *
501
+ * @example
502
+ * ```typescript
503
+ * // Simple copy
504
+ * await fsx.copyFile('/original.txt', '/backup.txt')
505
+ *
506
+ * // Fail if destination exists
507
+ * await fsx.copyFile('/src.txt', '/dst.txt', constants.COPYFILE_EXCL)
508
+ * ```
509
+ */
510
+ async copyFile(src, dest, _flags) {
511
+ src = this.normalizePath(src);
512
+ dest = this.normalizePath(dest);
513
+ await this.backend.copyFile(src, dest);
514
+ }
515
+ // ==================== Directory Operations ====================
516
+ /**
517
+ * Create a directory
518
+ *
519
+ * Creates a new directory. With recursive option, creates parent directories
520
+ * as needed (like `mkdir -p`).
521
+ *
522
+ * @param path - Path for the new directory
523
+ * @param options - Creation options
524
+ * @param options.recursive - Create parent directories if needed (default: false)
525
+ * @param options.mode - Directory permissions (default: 0o755)
526
+ * @throws {EEXIST} If directory already exists (unless recursive is true)
527
+ * @throws {ENOENT} If parent doesn't exist and recursive is false
528
+ *
529
+ * @example
530
+ * ```typescript
531
+ * // Create a single directory
532
+ * await fsx.mkdir('/mydir')
533
+ *
534
+ * // Create nested directories
535
+ * await fsx.mkdir('/a/b/c', { recursive: true })
536
+ * ```
537
+ */
538
+ async mkdir(path, options) {
539
+ path = this.normalizePath(path);
540
+ await this.backend.mkdir(path, {
541
+ recursive: options?.recursive ?? false,
542
+ mode: options?.mode ?? this.options.defaultDirMode,
543
+ });
544
+ // Emit watch event - 'rename' for new directory
545
+ this.watchManager.emit('rename', path);
546
+ }
547
+ /**
548
+ * Remove a directory
549
+ *
550
+ * Removes an empty directory. With recursive option, removes directory
551
+ * and all contents (like `rm -r`).
552
+ *
553
+ * @param path - Path to the directory
554
+ * @param options - Removal options
555
+ * @param options.recursive - Remove contents recursively (default: false)
556
+ * @throws {ENOENT} If directory does not exist
557
+ * @throws {ENOTDIR} If path is not a directory
558
+ * @throws {ENOTEMPTY} If directory is not empty and recursive is false
559
+ *
560
+ * @example
561
+ * ```typescript
562
+ * // Remove empty directory
563
+ * await fsx.rmdir('/empty-dir')
564
+ *
565
+ * // Remove directory and all contents
566
+ * await fsx.rmdir('/full-dir', { recursive: true })
567
+ * ```
568
+ */
569
+ async rmdir(path, options) {
570
+ path = this.normalizePath(path);
571
+ await this.backend.rmdir(path, {
572
+ recursive: options?.recursive ?? false,
573
+ });
574
+ // Emit watch event - 'rename' for directory deletion
575
+ this.watchManager.emit('rename', path);
576
+ }
577
+ /**
578
+ * Remove a file or directory
579
+ *
580
+ * Removes files or directories. With recursive option, removes directories
581
+ * and their contents. With force option, ignores non-existent paths.
582
+ *
583
+ * @param path - Path to remove
584
+ * @param options - Removal options
585
+ * @param options.recursive - Remove directories and contents (default: false)
586
+ * @param options.force - Ignore if path doesn't exist (default: false)
587
+ * @throws {ENOENT} If path doesn't exist and force is false
588
+ * @throws {EISDIR} If path is a directory and recursive is false
589
+ *
590
+ * @example
591
+ * ```typescript
592
+ * // Remove a file
593
+ * await fsx.rm('/file.txt')
594
+ *
595
+ * // Remove directory tree (like rm -rf)
596
+ * await fsx.rm('/directory', { recursive: true, force: true })
597
+ * ```
598
+ */
599
+ async rm(path, options) {
600
+ path = this.normalizePath(path);
601
+ // rm is implemented as unlink or rmdir depending on path type
602
+ try {
603
+ const stats = await this.backend.stat(path);
604
+ if (stats.isDirectory()) {
605
+ await this.backend.rmdir(path, { recursive: options?.recursive ?? false });
606
+ }
607
+ else {
608
+ await this.backend.unlink(path);
609
+ }
610
+ }
611
+ catch (error) {
612
+ // If force is true, ignore ENOENT
613
+ if (options?.force && error.message.includes('ENOENT')) {
614
+ return;
615
+ }
616
+ throw error;
617
+ }
618
+ // Emit watch event - 'rename' for deletion
619
+ this.watchManager.emit('rename', path);
620
+ }
621
+ /**
622
+ * Read directory contents
623
+ *
624
+ * Returns the contents of a directory. With withFileTypes option, returns
625
+ * Dirent objects with type information. With recursive option, includes
626
+ * contents of subdirectories.
627
+ *
628
+ * @param path - Path to the directory
629
+ * @param options - Read options
630
+ * @param options.withFileTypes - Return Dirent objects instead of strings (default: false)
631
+ * @param options.recursive - Include subdirectory contents (default: false)
632
+ * @returns Array of filenames or Dirent objects
633
+ * @throws {ENOENT} If directory does not exist
634
+ * @throws {ENOTDIR} If path is not a directory
635
+ *
636
+ * @example
637
+ * ```typescript
638
+ * // List filenames
639
+ * const files = await fsx.readdir('/mydir')
640
+ * // ['file1.txt', 'file2.txt', 'subdir']
641
+ *
642
+ * // List with file types
643
+ * const entries = await fsx.readdir('/mydir', { withFileTypes: true })
644
+ * entries.forEach(e => console.log(e.name, e.isDirectory()))
645
+ * ```
646
+ */
647
+ async readdir(path, options) {
648
+ path = this.normalizePath(path);
649
+ return this.backend.readdir(path, {
650
+ withFileTypes: options?.withFileTypes ?? false,
651
+ recursive: options?.recursive ?? false,
652
+ });
653
+ }
654
+ // ==================== Metadata Operations ====================
655
+ /**
656
+ * Get file or directory stats
657
+ *
658
+ * Returns metadata about a file or directory including size, permissions,
659
+ * timestamps, and type-checking methods. Follows symbolic links.
660
+ *
661
+ * @param path - Path to the file or directory
662
+ * @returns Stats object with file metadata and type-checking methods
663
+ * @throws {ENOENT} If the path does not exist
664
+ *
665
+ * @example
666
+ * ```typescript
667
+ * const stats = await fsx.stat('/myfile.txt')
668
+ * console.log(stats.size) // File size in bytes
669
+ * console.log(stats.isFile()) // true
670
+ * console.log(stats.mtime) // Last modification time
671
+ * ```
672
+ */
673
+ async stat(path) {
674
+ path = this.normalizePath(path);
675
+ return this.backend.stat(path);
676
+ }
677
+ /**
678
+ * Get file or directory stats without following symbolic links
679
+ *
680
+ * Like {@link stat}, but does not follow symbolic links. If the path is
681
+ * a symlink, returns information about the link itself rather than its target.
682
+ *
683
+ * @param path - Path to the file, directory, or symbolic link
684
+ * @returns Stats object with file metadata and type-checking methods
685
+ * @throws {ENOENT} If the path does not exist
686
+ *
687
+ * @example
688
+ * ```typescript
689
+ * // Check if something is a symlink
690
+ * const stats = await fsx.lstat('/link')
691
+ * if (stats.isSymbolicLink()) {
692
+ * const target = await fsx.readlink('/link')
693
+ * }
694
+ * ```
695
+ */
696
+ async lstat(path) {
697
+ path = this.normalizePath(path);
698
+ return this.backend.lstat(path);
699
+ }
700
+ /**
701
+ * Check file access permissions
702
+ *
703
+ * Tests whether the calling process can access the file at path.
704
+ * Throws an error if access is not permitted.
705
+ *
706
+ * @param path - Path to check
707
+ * @param mode - Access mode to check (default: F_OK for existence)
708
+ * - constants.F_OK: Check existence
709
+ * - constants.R_OK: Check read permission
710
+ * - constants.W_OK: Check write permission
711
+ * - constants.X_OK: Check execute permission
712
+ * @throws {ENOENT} If the path does not exist
713
+ * @throws {EACCES} If access is not permitted
714
+ *
715
+ * @example
716
+ * ```typescript
717
+ * // Check if file exists
718
+ * await fsx.access('/myfile.txt')
719
+ *
720
+ * // Check if file is readable and writable
721
+ * await fsx.access('/myfile.txt', constants.R_OK | constants.W_OK)
722
+ * ```
723
+ */
724
+ async access(path, _mode) {
725
+ path = this.normalizePath(path);
726
+ // Check existence via stat - full permission checks would need backend support
727
+ await this.backend.stat(path);
728
+ }
729
+ /**
730
+ * Check if a path exists
731
+ *
732
+ * A convenience method that returns a boolean instead of throwing.
733
+ * Prefer {@link access} when you need to check specific permissions.
734
+ *
735
+ * @param path - Path to check
736
+ * @returns true if the path exists, false otherwise
737
+ *
738
+ * @example
739
+ * ```typescript
740
+ * if (await fsx.exists('/config.json')) {
741
+ * const config = await fsx.readFile('/config.json')
742
+ * }
743
+ * ```
744
+ */
745
+ async exists(path) {
746
+ path = this.normalizePath(path);
747
+ return this.backend.exists(path);
748
+ }
749
+ /**
750
+ * Change file permissions
751
+ *
752
+ * Changes the permissions of a file or directory.
753
+ *
754
+ * @param path - Path to the file or directory
755
+ * @param mode - New permissions (octal, e.g., 0o755)
756
+ * @throws {ENOENT} If the path does not exist
757
+ *
758
+ * @example
759
+ * ```typescript
760
+ * // Make a script executable
761
+ * await fsx.chmod('/script.sh', 0o755)
762
+ *
763
+ * // Read-only for owner only
764
+ * await fsx.chmod('/secret.txt', 0o400)
765
+ * ```
766
+ */
767
+ async chmod(path, mode) {
768
+ path = this.normalizePath(path);
769
+ await this.backend.chmod(path, mode);
770
+ }
771
+ /**
772
+ * Change file ownership
773
+ *
774
+ * Changes the owner and group of a file or directory.
775
+ *
776
+ * @param path - Path to the file or directory
777
+ * @param uid - User ID of the new owner
778
+ * @param gid - Group ID of the new group
779
+ * @throws {ENOENT} If the path does not exist
780
+ *
781
+ * @example
782
+ * ```typescript
783
+ * await fsx.chown('/myfile.txt', 1000, 1000)
784
+ * ```
785
+ */
786
+ async chown(path, uid, gid) {
787
+ path = this.normalizePath(path);
788
+ await this.backend.chown(path, uid, gid);
789
+ }
790
+ /**
791
+ * Update file access and modification timestamps
792
+ *
793
+ * Sets the access time (atime) and modification time (mtime) of a file.
794
+ *
795
+ * @param path - Path to the file
796
+ * @param atime - New access time (Date or Unix timestamp in ms)
797
+ * @param mtime - New modification time (Date or Unix timestamp in ms)
798
+ * @throws {ENOENT} If the file does not exist
799
+ *
800
+ * @example
801
+ * ```typescript
802
+ * // Set timestamps to current time
803
+ * const now = new Date()
804
+ * await fsx.utimes('/myfile.txt', now, now)
805
+ *
806
+ * // Set to specific Unix timestamp
807
+ * await fsx.utimes('/myfile.txt', 1704067200000, 1704067200000)
808
+ * ```
809
+ */
810
+ async utimes(path, atime, mtime) {
811
+ path = this.normalizePath(path);
812
+ await this.backend.utimes(path, atime, mtime);
813
+ }
814
+ // ==================== Symbolic Links ====================
815
+ /**
816
+ * Create a symbolic link
817
+ *
818
+ * Creates a symbolic link at path pointing to target.
819
+ * The target can be a relative or absolute path.
820
+ *
821
+ * @param target - The path the symlink should point to
822
+ * @param path - Where to create the symlink
823
+ * @throws {EEXIST} If a file already exists at path
824
+ *
825
+ * @example
826
+ * ```typescript
827
+ * // Create symlink to a file
828
+ * await fsx.symlink('/data/config.json', '/config.json')
829
+ *
830
+ * // Create symlink with relative target
831
+ * await fsx.symlink('../shared/lib', '/app/lib')
832
+ * ```
833
+ */
834
+ async symlink(target, path) {
835
+ path = this.normalizePath(path);
836
+ await this.backend.symlink(target, path);
837
+ }
838
+ /**
839
+ * Create a hard link
840
+ *
841
+ * Creates a new directory entry (hard link) at newPath that references
842
+ * the same file as existingPath. Both paths will point to the same
843
+ * underlying file content.
844
+ *
845
+ * @param existingPath - Path to the existing file
846
+ * @param newPath - Path for the new hard link
847
+ * @throws {ENOENT} If existingPath does not exist
848
+ * @throws {EEXIST} If newPath already exists
849
+ *
850
+ * @example
851
+ * ```typescript
852
+ * await fsx.link('/original.txt', '/hardlink.txt')
853
+ * // Both paths now reference the same file
854
+ * ```
855
+ */
856
+ async link(existingPath, newPath) {
857
+ existingPath = this.normalizePath(existingPath);
858
+ newPath = this.normalizePath(newPath);
859
+ await this.backend.link(existingPath, newPath);
860
+ }
861
+ /**
862
+ * Read the target of a symbolic link
863
+ *
864
+ * Returns the path that a symbolic link points to.
865
+ *
866
+ * @param path - Path to the symbolic link
867
+ * @returns The target path (may be relative or absolute)
868
+ * @throws {ENOENT} If the path does not exist
869
+ * @throws {EINVAL} If the path is not a symbolic link
870
+ *
871
+ * @example
872
+ * ```typescript
873
+ * // Get symlink target
874
+ * const target = await fsx.readlink('/mylink')
875
+ * console.log(target) // '/actual/file/path'
876
+ * ```
877
+ */
878
+ async readlink(path) {
879
+ path = this.normalizePath(path);
880
+ return this.backend.readlink(path);
881
+ }
882
+ /**
883
+ * Resolve the absolute path, following symbolic links
884
+ *
885
+ * Returns the canonical absolute pathname by resolving `.`, `..`,
886
+ * and symbolic links.
887
+ *
888
+ * @param path - Path to resolve
889
+ * @returns The resolved absolute path
890
+ * @throws {ENOENT} If the path does not exist
891
+ *
892
+ * @example
893
+ * ```typescript
894
+ * // Resolve symlinks and relative components
895
+ * const real = await fsx.realpath('/app/../data/./link')
896
+ * console.log(real) // '/data/actual-file'
897
+ * ```
898
+ */
899
+ async realpath(path) {
900
+ path = this.normalizePath(path);
901
+ // Realpath resolves symlinks - for now just return the normalized path
902
+ // as full symlink resolution would need backend support
903
+ return path;
904
+ }
905
+ // ==================== Streams ====================
906
+ /**
907
+ * Create a readable stream for a file
908
+ *
909
+ * Returns a ReadableStream that can be used to read file contents
910
+ * in chunks. Useful for large files or when streaming to responses.
911
+ *
912
+ * @param path - Path to the file to read
913
+ * @param options - Stream options (start, end positions, highWaterMark)
914
+ * @returns A ReadableStream of Uint8Array chunks
915
+ * @throws {ENOENT} If the file does not exist
916
+ * @throws {EISDIR} If the path is a directory
917
+ *
918
+ * @example
919
+ * ```typescript
920
+ * const stream = await fsx.createReadStream('/large-file.bin')
921
+ * for await (const chunk of stream) {
922
+ * process.write(chunk)
923
+ * }
924
+ * ```
925
+ */
926
+ async createReadStream(path, options) {
927
+ path = this.normalizePath(path);
928
+ // Read entire file and wrap in a stream
929
+ const data = await this.backend.readFile(path);
930
+ // Apply start/end options if specified
931
+ let bytes = data;
932
+ if (options?.start !== undefined || options?.end !== undefined) {
933
+ const start = options?.start ?? 0;
934
+ const end = options?.end !== undefined ? options.end + 1 : data.length;
935
+ bytes = data.slice(start, end);
936
+ }
937
+ return new ReadableStream({
938
+ start(controller) {
939
+ controller.enqueue(bytes);
940
+ controller.close();
941
+ },
942
+ });
943
+ }
944
+ /**
945
+ * Create a writable stream for a file
946
+ *
947
+ * Returns a WritableStream that can be used to write file contents
948
+ * in chunks. The file is created if it doesn't exist.
949
+ *
950
+ * @param path - Path to the file to write
951
+ * @param options - Stream options (flags, mode, start position)
952
+ * @returns A WritableStream accepting Uint8Array chunks
953
+ *
954
+ * @example
955
+ * ```typescript
956
+ * const stream = await fsx.createWriteStream('/output.bin')
957
+ * const writer = stream.getWriter()
958
+ * await writer.write(new Uint8Array([1, 2, 3]))
959
+ * await writer.close()
960
+ * ```
961
+ */
962
+ async createWriteStream(path, options) {
963
+ const normalizedPath = this.normalizePath(path);
964
+ const backend = this.backend;
965
+ const defaultMode = this.options.defaultMode;
966
+ // Collect chunks and write on close
967
+ const chunks = [];
968
+ return new WritableStream({
969
+ write(chunk) {
970
+ chunks.push(chunk);
971
+ },
972
+ async close() {
973
+ // Concatenate all chunks
974
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
975
+ const data = new Uint8Array(totalLength);
976
+ let offset = 0;
977
+ for (const chunk of chunks) {
978
+ data.set(chunk, offset);
979
+ offset += chunk.length;
980
+ }
981
+ // Write to backend
982
+ await backend.writeFile(normalizedPath, data, {
983
+ mode: options?.mode ?? defaultMode,
984
+ flag: options?.flags,
985
+ });
986
+ },
987
+ });
988
+ }
989
+ // ==================== File Watching ====================
990
+ /**
991
+ * Watch a file or directory for changes
992
+ *
993
+ * Returns an FSWatcher that emits events when the file or directory changes.
994
+ * Events are emitted synchronously when filesystem operations occur on this
995
+ * FSx instance.
996
+ *
997
+ * Event types:
998
+ * - 'change': Fired when file content is modified
999
+ * - 'rename': Fired when a file/directory is created, deleted, or renamed
1000
+ *
1001
+ * @param path - Path to watch (file or directory)
1002
+ * @param options - Watch options
1003
+ * @param options.recursive - Watch subdirectories recursively (default: false)
1004
+ * @param options.persistent - Keep process alive while watching (default: true)
1005
+ * @param options.encoding - Encoding for filenames (default: 'utf-8')
1006
+ * @param listener - Callback for change events (eventType: 'change'|'rename', filename)
1007
+ * @returns An FSWatcher object with close(), ref(), and unref() methods
1008
+ *
1009
+ * @example
1010
+ * ```typescript
1011
+ * // Watch a directory for changes
1012
+ * const watcher = fsx.watch('/mydir', {}, (event, filename) => {
1013
+ * console.log(`${event}: ${filename}`)
1014
+ * })
1015
+ *
1016
+ * // Watch recursively
1017
+ * const deepWatcher = fsx.watch('/root', { recursive: true }, (event, filename) => {
1018
+ * console.log(`${event}: ${filename}`)
1019
+ * })
1020
+ *
1021
+ * // Later, stop watching
1022
+ * watcher.close()
1023
+ * ```
1024
+ */
1025
+ watch(path, options, listener) {
1026
+ path = this.normalizePath(path);
1027
+ // Register the watcher with the WatchManager
1028
+ const recursive = options?.recursive ?? false;
1029
+ const watchEntry = listener
1030
+ ? this.watchManager.addWatcher(path, recursive, listener)
1031
+ : null;
1032
+ // Create the FSWatcher object
1033
+ const watcher = {
1034
+ close: () => {
1035
+ if (watchEntry) {
1036
+ this.watchManager.removeWatcher(watchEntry);
1037
+ }
1038
+ },
1039
+ ref: () => watcher,
1040
+ unref: () => watcher,
1041
+ };
1042
+ return watcher;
1043
+ }
1044
+ // ==================== Utility ====================
1045
+ /**
1046
+ * Truncate a file to a specified length
1047
+ *
1048
+ * If the file is larger than the specified length, the extra data is discarded.
1049
+ * If smaller, the file is extended with null bytes.
1050
+ *
1051
+ * @param path - Path to the file
1052
+ * @param length - New file length in bytes (default: 0)
1053
+ * @throws {ENOENT} If the file does not exist
1054
+ * @throws {EISDIR} If the path is a directory
1055
+ *
1056
+ * @example
1057
+ * ```typescript
1058
+ * // Clear a file
1059
+ * await fsx.truncate('/myfile.txt')
1060
+ *
1061
+ * // Truncate to first 100 bytes
1062
+ * await fsx.truncate('/myfile.txt', 100)
1063
+ * ```
1064
+ */
1065
+ async truncate(path, length) {
1066
+ path = this.normalizePath(path);
1067
+ const targetLength = length ?? 0;
1068
+ // Read current content
1069
+ const data = await this.backend.readFile(path);
1070
+ // Truncate or extend
1071
+ let newData;
1072
+ if (data.length > targetLength) {
1073
+ newData = data.slice(0, targetLength);
1074
+ }
1075
+ else if (data.length < targetLength) {
1076
+ newData = new Uint8Array(targetLength);
1077
+ newData.set(data);
1078
+ // Rest is already zero-filled
1079
+ }
1080
+ else {
1081
+ return; // No change needed
1082
+ }
1083
+ await this.backend.writeFile(path, newData);
1084
+ }
1085
+ /**
1086
+ * Open a file and get a file handle for low-level operations
1087
+ *
1088
+ * Returns a FileHandle that provides fine-grained control over file I/O,
1089
+ * including positioned reads/writes and file synchronization.
1090
+ *
1091
+ * @param path - Path to the file
1092
+ * @param flags - Open mode: 'r' (read), 'w' (write), 'a' (append), etc.
1093
+ * @param mode - File permissions for newly created files (default: 0o644)
1094
+ * @returns A FileHandle for low-level file operations
1095
+ * @throws {ENOENT} If file doesn't exist and flags don't include create
1096
+ *
1097
+ * @example
1098
+ * ```typescript
1099
+ * const handle = await fsx.open('/data.bin', 'r+')
1100
+ * try {
1101
+ * const buffer = new Uint8Array(1024)
1102
+ * const { bytesRead } = await handle.read(buffer, 0, 1024, 0)
1103
+ * await handle.write(new Uint8Array([1, 2, 3]), 0)
1104
+ * await handle.sync()
1105
+ * } finally {
1106
+ * await handle.close()
1107
+ * }
1108
+ * ```
1109
+ */
1110
+ async open(path, flags, _mode) {
1111
+ path = this.normalizePath(path);
1112
+ return this.createFileHandle(path, flags);
1113
+ }
1114
+ /**
1115
+ * Create a FileHandle object for low-level file operations
1116
+ *
1117
+ * @param path - The file path
1118
+ * @param flags - Open flags
1119
+ * @returns A FileHandle with read, write, stat, sync, and close methods
1120
+ */
1121
+ createFileHandle(path, _flags) {
1122
+ const backend = this.backend;
1123
+ let fileData = null;
1124
+ let modified = false;
1125
+ return {
1126
+ fd: 0, // Placeholder - we use path-based operations
1127
+ read: async (buffer, offset, length, position) => {
1128
+ if (!fileData) {
1129
+ fileData = await backend.readFile(path);
1130
+ }
1131
+ const readLength = length ?? buffer.length;
1132
+ const readPosition = position ?? 0;
1133
+ const targetOffset = offset ?? 0;
1134
+ const bytesToRead = Math.min(readLength, fileData.length - readPosition);
1135
+ for (let i = 0; i < bytesToRead; i++) {
1136
+ buffer[targetOffset + i] = fileData[readPosition + i];
1137
+ }
1138
+ return { bytesRead: bytesToRead, buffer };
1139
+ },
1140
+ write: async (data, _position) => {
1141
+ const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : data;
1142
+ fileData = bytes;
1143
+ modified = true;
1144
+ return { bytesWritten: bytes.length };
1145
+ },
1146
+ stat: () => backend.stat(path),
1147
+ truncate: async (length) => {
1148
+ if (!fileData) {
1149
+ fileData = await backend.readFile(path);
1150
+ }
1151
+ const targetLength = length ?? 0;
1152
+ if (fileData.length > targetLength) {
1153
+ fileData = fileData.slice(0, targetLength);
1154
+ }
1155
+ else if (fileData.length < targetLength) {
1156
+ const newData = new Uint8Array(targetLength);
1157
+ newData.set(fileData);
1158
+ fileData = newData;
1159
+ }
1160
+ modified = true;
1161
+ },
1162
+ sync: async () => {
1163
+ if (modified && fileData) {
1164
+ await backend.writeFile(path, fileData);
1165
+ modified = false;
1166
+ }
1167
+ },
1168
+ close: async () => {
1169
+ if (modified && fileData) {
1170
+ await backend.writeFile(path, fileData);
1171
+ }
1172
+ fileData = null;
1173
+ modified = false;
1174
+ },
1175
+ createReadStream: (_options) => {
1176
+ throw new Error('FileHandle.createReadStream is not implemented');
1177
+ },
1178
+ createWriteStream: (_options) => {
1179
+ throw new Error('FileHandle.createWriteStream is not implemented');
1180
+ },
1181
+ };
1182
+ }
1183
+ }
1184
+ //# sourceMappingURL=fsx.js.map