@dotdo/postgres 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 (1129) hide show
  1. package/README.md +868 -0
  2. package/dist/cdc/change-stream.d.ts +44 -0
  3. package/dist/cdc/change-stream.d.ts.map +1 -0
  4. package/dist/cdc/change-stream.js +95 -0
  5. package/dist/cdc/change-stream.js.map +1 -0
  6. package/dist/cdc/filter.d.ts +58 -0
  7. package/dist/cdc/filter.d.ts.map +1 -0
  8. package/dist/cdc/filter.js +520 -0
  9. package/dist/cdc/filter.js.map +1 -0
  10. package/dist/cdc/index.d.ts +47 -0
  11. package/dist/cdc/index.d.ts.map +1 -0
  12. package/dist/cdc/index.js +50 -0
  13. package/dist/cdc/index.js.map +1 -0
  14. package/dist/cdc/resume-token.d.ts +60 -0
  15. package/dist/cdc/resume-token.d.ts.map +1 -0
  16. package/dist/cdc/resume-token.js +228 -0
  17. package/dist/cdc/resume-token.js.map +1 -0
  18. package/dist/cdc/transport/index.d.ts +7 -0
  19. package/dist/cdc/transport/index.d.ts.map +1 -0
  20. package/dist/cdc/transport/index.js +7 -0
  21. package/dist/cdc/transport/index.js.map +1 -0
  22. package/dist/cdc/transport/sse.d.ts +120 -0
  23. package/dist/cdc/transport/sse.d.ts.map +1 -0
  24. package/dist/cdc/transport/sse.js +590 -0
  25. package/dist/cdc/transport/sse.js.map +1 -0
  26. package/dist/cdc/transport/websocket.d.ts +130 -0
  27. package/dist/cdc/transport/websocket.d.ts.map +1 -0
  28. package/dist/cdc/transport/websocket.js +688 -0
  29. package/dist/cdc/transport/websocket.js.map +1 -0
  30. package/dist/cdc/types.d.ts +306 -0
  31. package/dist/cdc/types.d.ts.map +1 -0
  32. package/dist/cdc/types.js +8 -0
  33. package/dist/cdc/types.js.map +1 -0
  34. package/dist/config/index.d.ts +25 -0
  35. package/dist/config/index.d.ts.map +1 -0
  36. package/dist/config/index.js +25 -0
  37. package/dist/config/index.js.map +1 -0
  38. package/dist/config/memory.d.ts +139 -0
  39. package/dist/config/memory.d.ts.map +1 -0
  40. package/dist/config/memory.js +157 -0
  41. package/dist/config/memory.js.map +1 -0
  42. package/dist/config/storage.d.ts +157 -0
  43. package/dist/config/storage.d.ts.map +1 -0
  44. package/dist/config/storage.js +178 -0
  45. package/dist/config/storage.js.map +1 -0
  46. package/dist/config/streaming.d.ts +117 -0
  47. package/dist/config/streaming.d.ts.map +1 -0
  48. package/dist/config/streaming.js +132 -0
  49. package/dist/config/streaming.js.map +1 -0
  50. package/dist/config/timeouts.d.ts +168 -0
  51. package/dist/config/timeouts.d.ts.map +1 -0
  52. package/dist/config/timeouts.js +192 -0
  53. package/dist/config/timeouts.js.map +1 -0
  54. package/dist/extensions/config.d.ts +89 -0
  55. package/dist/extensions/config.d.ts.map +1 -0
  56. package/dist/extensions/config.js +216 -0
  57. package/dist/extensions/config.js.map +1 -0
  58. package/dist/extensions/geo.d.ts +452 -0
  59. package/dist/extensions/geo.d.ts.map +1 -0
  60. package/dist/extensions/geo.js +583 -0
  61. package/dist/extensions/geo.js.map +1 -0
  62. package/dist/extensions/index.d.ts +167 -0
  63. package/dist/extensions/index.d.ts.map +1 -0
  64. package/dist/extensions/index.js +99 -0
  65. package/dist/extensions/index.js.map +1 -0
  66. package/dist/extensions/loader.d.ts +226 -0
  67. package/dist/extensions/loader.d.ts.map +1 -0
  68. package/dist/extensions/loader.js +456 -0
  69. package/dist/extensions/loader.js.map +1 -0
  70. package/dist/extensions/pgmq-lite.d.ts +330 -0
  71. package/dist/extensions/pgmq-lite.d.ts.map +1 -0
  72. package/dist/extensions/pgmq-lite.js +648 -0
  73. package/dist/extensions/pgmq-lite.js.map +1 -0
  74. package/dist/extensions/plugins.d.ts +260 -0
  75. package/dist/extensions/plugins.d.ts.map +1 -0
  76. package/dist/extensions/plugins.js +535 -0
  77. package/dist/extensions/plugins.js.map +1 -0
  78. package/dist/extensions/registry.d.ts +93 -0
  79. package/dist/extensions/registry.d.ts.map +1 -0
  80. package/dist/extensions/registry.js +182 -0
  81. package/dist/extensions/registry.js.map +1 -0
  82. package/dist/extensions/vector.d.ts +106 -0
  83. package/dist/extensions/vector.d.ts.map +1 -0
  84. package/dist/extensions/vector.js +129 -0
  85. package/dist/extensions/vector.js.map +1 -0
  86. package/dist/iceberg/analytics.d.ts +279 -0
  87. package/dist/iceberg/analytics.d.ts.map +1 -0
  88. package/dist/iceberg/analytics.js +448 -0
  89. package/dist/iceberg/analytics.js.map +1 -0
  90. package/dist/iceberg/catalog-api.d.ts +39 -0
  91. package/dist/iceberg/catalog-api.d.ts.map +1 -0
  92. package/dist/iceberg/catalog-api.js +388 -0
  93. package/dist/iceberg/catalog-api.js.map +1 -0
  94. package/dist/iceberg/catalog.d.ts +401 -0
  95. package/dist/iceberg/catalog.d.ts.map +1 -0
  96. package/dist/iceberg/catalog.js +677 -0
  97. package/dist/iceberg/catalog.js.map +1 -0
  98. package/dist/iceberg/duckdb-wasm.d.ts +447 -0
  99. package/dist/iceberg/duckdb-wasm.d.ts.map +1 -0
  100. package/dist/iceberg/duckdb-wasm.js +600 -0
  101. package/dist/iceberg/duckdb-wasm.js.map +1 -0
  102. package/dist/iceberg/index.d.ts +92 -0
  103. package/dist/iceberg/index.d.ts.map +1 -0
  104. package/dist/iceberg/index.js +119 -0
  105. package/dist/iceberg/index.js.map +1 -0
  106. package/dist/iceberg/metadata.d.ts +214 -0
  107. package/dist/iceberg/metadata.d.ts.map +1 -0
  108. package/dist/iceberg/metadata.js +535 -0
  109. package/dist/iceberg/metadata.js.map +1 -0
  110. package/dist/iceberg/optimizer.d.ts +296 -0
  111. package/dist/iceberg/optimizer.d.ts.map +1 -0
  112. package/dist/iceberg/optimizer.js +889 -0
  113. package/dist/iceberg/optimizer.js.map +1 -0
  114. package/dist/iceberg/parquet.d.ts +447 -0
  115. package/dist/iceberg/parquet.d.ts.map +1 -0
  116. package/dist/iceberg/parquet.js +1225 -0
  117. package/dist/iceberg/parquet.js.map +1 -0
  118. package/dist/iceberg/r2-organization.d.ts +422 -0
  119. package/dist/iceberg/r2-organization.d.ts.map +1 -0
  120. package/dist/iceberg/r2-organization.js +672 -0
  121. package/dist/iceberg/r2-organization.js.map +1 -0
  122. package/dist/iceberg/scheduler-do-example.d.ts +158 -0
  123. package/dist/iceberg/scheduler-do-example.d.ts.map +1 -0
  124. package/dist/iceberg/scheduler-do-example.js +261 -0
  125. package/dist/iceberg/scheduler-do-example.js.map +1 -0
  126. package/dist/iceberg/scheduler.d.ts +434 -0
  127. package/dist/iceberg/scheduler.d.ts.map +1 -0
  128. package/dist/iceberg/scheduler.js +818 -0
  129. package/dist/iceberg/scheduler.js.map +1 -0
  130. package/dist/iceberg/schema.d.ts +149 -0
  131. package/dist/iceberg/schema.d.ts.map +1 -0
  132. package/dist/iceberg/schema.js +525 -0
  133. package/dist/iceberg/schema.js.map +1 -0
  134. package/dist/iceberg/snapshot-manager.d.ts +406 -0
  135. package/dist/iceberg/snapshot-manager.d.ts.map +1 -0
  136. package/dist/iceberg/snapshot-manager.js +934 -0
  137. package/dist/iceberg/snapshot-manager.js.map +1 -0
  138. package/dist/iceberg/sql-router.d.ts +194 -0
  139. package/dist/iceberg/sql-router.d.ts.map +1 -0
  140. package/dist/iceberg/sql-router.js +180 -0
  141. package/dist/iceberg/sql-router.js.map +1 -0
  142. package/dist/iceberg/test-fixtures.d.ts +151 -0
  143. package/dist/iceberg/test-fixtures.d.ts.map +1 -0
  144. package/dist/iceberg/test-fixtures.js +446 -0
  145. package/dist/iceberg/test-fixtures.js.map +1 -0
  146. package/dist/iceberg/time-travel-api.d.ts +102 -0
  147. package/dist/iceberg/time-travel-api.d.ts.map +1 -0
  148. package/dist/iceberg/time-travel-api.js +437 -0
  149. package/dist/iceberg/time-travel-api.js.map +1 -0
  150. package/dist/iceberg/time-travel.d.ts +293 -0
  151. package/dist/iceberg/time-travel.d.ts.map +1 -0
  152. package/dist/iceberg/time-travel.js +689 -0
  153. package/dist/iceberg/time-travel.js.map +1 -0
  154. package/dist/iceberg/transformer.d.ts +356 -0
  155. package/dist/iceberg/transformer.d.ts.map +1 -0
  156. package/dist/iceberg/transformer.js +770 -0
  157. package/dist/iceberg/transformer.js.map +1 -0
  158. package/dist/iceberg/types.d.ts +318 -0
  159. package/dist/iceberg/types.d.ts.map +1 -0
  160. package/dist/iceberg/types.js +9 -0
  161. package/dist/iceberg/types.js.map +1 -0
  162. package/dist/iceberg/writer.d.ts +144 -0
  163. package/dist/iceberg/writer.d.ts.map +1 -0
  164. package/dist/iceberg/writer.js +452 -0
  165. package/dist/iceberg/writer.js.map +1 -0
  166. package/dist/index.d.ts +50 -0
  167. package/dist/index.d.ts.map +1 -0
  168. package/dist/index.js +69 -0
  169. package/dist/index.js.map +1 -0
  170. package/dist/lineage/index.d.ts +11 -0
  171. package/dist/lineage/index.d.ts.map +1 -0
  172. package/dist/lineage/index.js +11 -0
  173. package/dist/lineage/index.js.map +1 -0
  174. package/dist/lineage/integration.d.ts +134 -0
  175. package/dist/lineage/integration.d.ts.map +1 -0
  176. package/dist/lineage/integration.js +258 -0
  177. package/dist/lineage/integration.js.map +1 -0
  178. package/dist/lineage/tracker.d.ts +189 -0
  179. package/dist/lineage/tracker.d.ts.map +1 -0
  180. package/dist/lineage/tracker.js +1352 -0
  181. package/dist/lineage/tracker.js.map +1 -0
  182. package/dist/lineage/types.d.ts +318 -0
  183. package/dist/lineage/types.d.ts.map +1 -0
  184. package/dist/lineage/types.js +9 -0
  185. package/dist/lineage/types.js.map +1 -0
  186. package/dist/middleware/index.d.ts +11 -0
  187. package/dist/middleware/index.d.ts.map +1 -0
  188. package/dist/middleware/index.js +16 -0
  189. package/dist/middleware/index.js.map +1 -0
  190. package/dist/middleware/rate-limit.d.ts +397 -0
  191. package/dist/middleware/rate-limit.d.ts.map +1 -0
  192. package/dist/middleware/rate-limit.js +507 -0
  193. package/dist/middleware/rate-limit.js.map +1 -0
  194. package/dist/migration-tooling/external-migration.d.ts +601 -0
  195. package/dist/migration-tooling/external-migration.d.ts.map +1 -0
  196. package/dist/migration-tooling/external-migration.js +1612 -0
  197. package/dist/migration-tooling/external-migration.js.map +1 -0
  198. package/dist/migration-tooling/index.d.ts +19 -0
  199. package/dist/migration-tooling/index.d.ts.map +1 -0
  200. package/dist/migration-tooling/index.js +19 -0
  201. package/dist/migration-tooling/index.js.map +1 -0
  202. package/dist/migrations/auto-migrator.d.ts +289 -0
  203. package/dist/migrations/auto-migrator.d.ts.map +1 -0
  204. package/dist/migrations/auto-migrator.js +396 -0
  205. package/dist/migrations/auto-migrator.js.map +1 -0
  206. package/dist/migrations/bulk-orchestrator.d.ts +403 -0
  207. package/dist/migrations/bulk-orchestrator.d.ts.map +1 -0
  208. package/dist/migrations/bulk-orchestrator.js +646 -0
  209. package/dist/migrations/bulk-orchestrator.js.map +1 -0
  210. package/dist/migrations/compatibility.d.ts +216 -0
  211. package/dist/migrations/compatibility.d.ts.map +1 -0
  212. package/dist/migrations/compatibility.js +651 -0
  213. package/dist/migrations/compatibility.js.map +1 -0
  214. package/dist/migrations/do-migrations.d.ts +101 -0
  215. package/dist/migrations/do-migrations.d.ts.map +1 -0
  216. package/dist/migrations/do-migrations.js +1060 -0
  217. package/dist/migrations/do-migrations.js.map +1 -0
  218. package/dist/migrations/do-migrations.types.d.ts +550 -0
  219. package/dist/migrations/do-migrations.types.d.ts.map +1 -0
  220. package/dist/migrations/do-migrations.types.js +15 -0
  221. package/dist/migrations/do-migrations.types.js.map +1 -0
  222. package/dist/migrations/drizzle-compat.d.ts +163 -0
  223. package/dist/migrations/drizzle-compat.d.ts.map +1 -0
  224. package/dist/migrations/drizzle-compat.js +273 -0
  225. package/dist/migrations/drizzle-compat.js.map +1 -0
  226. package/dist/migrations/index.d.ts +109 -0
  227. package/dist/migrations/index.d.ts.map +1 -0
  228. package/dist/migrations/index.js +127 -0
  229. package/dist/migrations/index.js.map +1 -0
  230. package/dist/migrations/migration-api.d.ts +161 -0
  231. package/dist/migrations/migration-api.d.ts.map +1 -0
  232. package/dist/migrations/migration-api.js +499 -0
  233. package/dist/migrations/migration-api.js.map +1 -0
  234. package/dist/migrations/progress-tracker-do.d.ts +195 -0
  235. package/dist/migrations/progress-tracker-do.d.ts.map +1 -0
  236. package/dist/migrations/progress-tracker-do.js +339 -0
  237. package/dist/migrations/progress-tracker-do.js.map +1 -0
  238. package/dist/migrations/progress-tracker-kv.d.ts +103 -0
  239. package/dist/migrations/progress-tracker-kv.d.ts.map +1 -0
  240. package/dist/migrations/progress-tracker-kv.js +231 -0
  241. package/dist/migrations/progress-tracker-kv.js.map +1 -0
  242. package/dist/migrations/progress-tracker.d.ts +320 -0
  243. package/dist/migrations/progress-tracker.d.ts.map +1 -0
  244. package/dist/migrations/progress-tracker.js +443 -0
  245. package/dist/migrations/progress-tracker.js.map +1 -0
  246. package/dist/migrations/registry.d.ts +231 -0
  247. package/dist/migrations/registry.d.ts.map +1 -0
  248. package/dist/migrations/registry.js +376 -0
  249. package/dist/migrations/registry.js.map +1 -0
  250. package/dist/migrations/runner.d.ts +197 -0
  251. package/dist/migrations/runner.d.ts.map +1 -0
  252. package/dist/migrations/runner.js +1167 -0
  253. package/dist/migrations/runner.js.map +1 -0
  254. package/dist/migrations/schema-generator.d.ts +111 -0
  255. package/dist/migrations/schema-generator.d.ts.map +1 -0
  256. package/dist/migrations/schema-generator.js +335 -0
  257. package/dist/migrations/schema-generator.js.map +1 -0
  258. package/dist/migrations/testing.d.ts +321 -0
  259. package/dist/migrations/testing.d.ts.map +1 -0
  260. package/dist/migrations/testing.js +645 -0
  261. package/dist/migrations/testing.js.map +1 -0
  262. package/dist/migrations/types.d.ts +503 -0
  263. package/dist/migrations/types.d.ts.map +1 -0
  264. package/dist/migrations/types.js +11 -0
  265. package/dist/migrations/types.js.map +1 -0
  266. package/dist/migrations/validator.d.ts +215 -0
  267. package/dist/migrations/validator.d.ts.map +1 -0
  268. package/dist/migrations/validator.js +494 -0
  269. package/dist/migrations/validator.js.map +1 -0
  270. package/dist/observability/alerting.d.ts +116 -0
  271. package/dist/observability/alerting.d.ts.map +1 -0
  272. package/dist/observability/alerting.js +353 -0
  273. package/dist/observability/alerting.js.map +1 -0
  274. package/dist/observability/analytics-engine.d.ts +357 -0
  275. package/dist/observability/analytics-engine.d.ts.map +1 -0
  276. package/dist/observability/analytics-engine.js +430 -0
  277. package/dist/observability/analytics-engine.js.map +1 -0
  278. package/dist/observability/cost-metrics.d.ts +269 -0
  279. package/dist/observability/cost-metrics.d.ts.map +1 -0
  280. package/dist/observability/cost-metrics.js +560 -0
  281. package/dist/observability/cost-metrics.js.map +1 -0
  282. package/dist/observability/cross-do-tracing.d.ts +305 -0
  283. package/dist/observability/cross-do-tracing.d.ts.map +1 -0
  284. package/dist/observability/cross-do-tracing.js +431 -0
  285. package/dist/observability/cross-do-tracing.js.map +1 -0
  286. package/dist/observability/error-rate-collector.d.ts +163 -0
  287. package/dist/observability/error-rate-collector.d.ts.map +1 -0
  288. package/dist/observability/error-rate-collector.js +306 -0
  289. package/dist/observability/error-rate-collector.js.map +1 -0
  290. package/dist/observability/exporters.d.ts +231 -0
  291. package/dist/observability/exporters.d.ts.map +1 -0
  292. package/dist/observability/exporters.js +479 -0
  293. package/dist/observability/exporters.js.map +1 -0
  294. package/dist/observability/health-check.d.ts +106 -0
  295. package/dist/observability/health-check.d.ts.map +1 -0
  296. package/dist/observability/health-check.js +243 -0
  297. package/dist/observability/health-check.js.map +1 -0
  298. package/dist/observability/index.d.ts +297 -0
  299. package/dist/observability/index.d.ts.map +1 -0
  300. package/dist/observability/index.js +455 -0
  301. package/dist/observability/index.js.map +1 -0
  302. package/dist/observability/instrumentation.d.ts +222 -0
  303. package/dist/observability/instrumentation.d.ts.map +1 -0
  304. package/dist/observability/instrumentation.js +532 -0
  305. package/dist/observability/instrumentation.js.map +1 -0
  306. package/dist/observability/memory-metrics.d.ts +227 -0
  307. package/dist/observability/memory-metrics.d.ts.map +1 -0
  308. package/dist/observability/memory-metrics.js +688 -0
  309. package/dist/observability/memory-metrics.js.map +1 -0
  310. package/dist/observability/metrics-endpoint.d.ts +91 -0
  311. package/dist/observability/metrics-endpoint.d.ts.map +1 -0
  312. package/dist/observability/metrics-endpoint.js +246 -0
  313. package/dist/observability/metrics-endpoint.js.map +1 -0
  314. package/dist/observability/metrics.d.ts +88 -0
  315. package/dist/observability/metrics.d.ts.map +1 -0
  316. package/dist/observability/metrics.js +253 -0
  317. package/dist/observability/metrics.js.map +1 -0
  318. package/dist/observability/observability-features.d.ts +488 -0
  319. package/dist/observability/observability-features.d.ts.map +1 -0
  320. package/dist/observability/observability-features.js +773 -0
  321. package/dist/observability/observability-features.js.map +1 -0
  322. package/dist/observability/prometheus.d.ts +39 -0
  323. package/dist/observability/prometheus.d.ts.map +1 -0
  324. package/dist/observability/prometheus.js +120 -0
  325. package/dist/observability/prometheus.js.map +1 -0
  326. package/dist/observability/propagation.d.ts +126 -0
  327. package/dist/observability/propagation.d.ts.map +1 -0
  328. package/dist/observability/propagation.js +234 -0
  329. package/dist/observability/propagation.js.map +1 -0
  330. package/dist/observability/query-latency.d.ts +243 -0
  331. package/dist/observability/query-latency.d.ts.map +1 -0
  332. package/dist/observability/query-latency.js +292 -0
  333. package/dist/observability/query-latency.js.map +1 -0
  334. package/dist/observability/query-performance.d.ts +169 -0
  335. package/dist/observability/query-performance.d.ts.map +1 -0
  336. package/dist/observability/query-performance.js +290 -0
  337. package/dist/observability/query-performance.js.map +1 -0
  338. package/dist/observability/storage-tier-metrics.d.ts +174 -0
  339. package/dist/observability/storage-tier-metrics.d.ts.map +1 -0
  340. package/dist/observability/storage-tier-metrics.js +306 -0
  341. package/dist/observability/storage-tier-metrics.js.map +1 -0
  342. package/dist/observability/tier-cost-optimizer.d.ts +155 -0
  343. package/dist/observability/tier-cost-optimizer.d.ts.map +1 -0
  344. package/dist/observability/tier-cost-optimizer.js +536 -0
  345. package/dist/observability/tier-cost-optimizer.js.map +1 -0
  346. package/dist/observability/tracer.d.ts +149 -0
  347. package/dist/observability/tracer.d.ts.map +1 -0
  348. package/dist/observability/tracer.js +435 -0
  349. package/dist/observability/tracer.js.map +1 -0
  350. package/dist/observability/types.d.ts +402 -0
  351. package/dist/observability/types.d.ts.map +1 -0
  352. package/dist/observability/types.js +103 -0
  353. package/dist/observability/types.js.map +1 -0
  354. package/dist/pglite/workers-pglite.d.ts +138 -0
  355. package/dist/pglite/workers-pglite.d.ts.map +1 -0
  356. package/dist/pglite/workers-pglite.js +143 -0
  357. package/dist/pglite/workers-pglite.js.map +1 -0
  358. package/dist/pglite-assets/pglite.data +0 -0
  359. package/dist/pglite-assets/pglite.wasm +0 -0
  360. package/dist/playground/index.d.ts +52 -0
  361. package/dist/playground/index.d.ts.map +1 -0
  362. package/dist/playground/index.js +55 -0
  363. package/dist/playground/index.js.map +1 -0
  364. package/dist/playground/keyboard-shortcuts.d.ts +116 -0
  365. package/dist/playground/keyboard-shortcuts.d.ts.map +1 -0
  366. package/dist/playground/keyboard-shortcuts.js +588 -0
  367. package/dist/playground/keyboard-shortcuts.js.map +1 -0
  368. package/dist/playground/playground.d.ts +82 -0
  369. package/dist/playground/playground.d.ts.map +1 -0
  370. package/dist/playground/playground.js +271 -0
  371. package/dist/playground/playground.js.map +1 -0
  372. package/dist/playground/query-executor.d.ts +115 -0
  373. package/dist/playground/query-executor.d.ts.map +1 -0
  374. package/dist/playground/query-executor.js +558 -0
  375. package/dist/playground/query-executor.js.map +1 -0
  376. package/dist/playground/query-history.d.ts +92 -0
  377. package/dist/playground/query-history.d.ts.map +1 -0
  378. package/dist/playground/query-history.js +259 -0
  379. package/dist/playground/query-history.js.map +1 -0
  380. package/dist/playground/result-formatter.d.ts +59 -0
  381. package/dist/playground/result-formatter.d.ts.map +1 -0
  382. package/dist/playground/result-formatter.js +341 -0
  383. package/dist/playground/result-formatter.js.map +1 -0
  384. package/dist/playground/sample-datasets.d.ts +77 -0
  385. package/dist/playground/sample-datasets.d.ts.map +1 -0
  386. package/dist/playground/sample-datasets.js +641 -0
  387. package/dist/playground/sample-datasets.js.map +1 -0
  388. package/dist/playground/sample-queries.d.ts +73 -0
  389. package/dist/playground/sample-queries.d.ts.map +1 -0
  390. package/dist/playground/sample-queries.js +1095 -0
  391. package/dist/playground/sample-queries.js.map +1 -0
  392. package/dist/playground/schema-explorer.d.ts +55 -0
  393. package/dist/playground/schema-explorer.d.ts.map +1 -0
  394. package/dist/playground/schema-explorer.js +473 -0
  395. package/dist/playground/schema-explorer.js.map +1 -0
  396. package/dist/playground/types.d.ts +430 -0
  397. package/dist/playground/types.d.ts.map +1 -0
  398. package/dist/playground/types.js +10 -0
  399. package/dist/playground/types.js.map +1 -0
  400. package/dist/readonly/cache-reader.d.ts +145 -0
  401. package/dist/readonly/cache-reader.d.ts.map +1 -0
  402. package/dist/readonly/cache-reader.js +198 -0
  403. package/dist/readonly/cache-reader.js.map +1 -0
  404. package/dist/readonly/config.d.ts +74 -0
  405. package/dist/readonly/config.d.ts.map +1 -0
  406. package/dist/readonly/config.js +67 -0
  407. package/dist/readonly/config.js.map +1 -0
  408. package/dist/readonly/index.d.ts +22 -0
  409. package/dist/readonly/index.d.ts.map +1 -0
  410. package/dist/readonly/index.js +17 -0
  411. package/dist/readonly/index.js.map +1 -0
  412. package/dist/readonly/pglite-wrapper.d.ts +82 -0
  413. package/dist/readonly/pglite-wrapper.d.ts.map +1 -0
  414. package/dist/readonly/pglite-wrapper.js +123 -0
  415. package/dist/readonly/pglite-wrapper.js.map +1 -0
  416. package/dist/readonly/worker.d.ts +142 -0
  417. package/dist/readonly/worker.d.ts.map +1 -0
  418. package/dist/readonly/worker.js +187 -0
  419. package/dist/readonly/worker.js.map +1 -0
  420. package/dist/readonly/write-blocker.d.ts +47 -0
  421. package/dist/readonly/write-blocker.d.ts.map +1 -0
  422. package/dist/readonly/write-blocker.js +136 -0
  423. package/dist/readonly/write-blocker.js.map +1 -0
  424. package/dist/recovery/disaster-recovery.d.ts +326 -0
  425. package/dist/recovery/disaster-recovery.d.ts.map +1 -0
  426. package/dist/recovery/disaster-recovery.js +799 -0
  427. package/dist/recovery/disaster-recovery.js.map +1 -0
  428. package/dist/recovery/index.d.ts +12 -0
  429. package/dist/recovery/index.d.ts.map +1 -0
  430. package/dist/recovery/index.js +12 -0
  431. package/dist/recovery/index.js.map +1 -0
  432. package/dist/recovery/parquet-parser.d.ts +321 -0
  433. package/dist/recovery/parquet-parser.d.ts.map +1 -0
  434. package/dist/recovery/parquet-parser.js +797 -0
  435. package/dist/recovery/parquet-parser.js.map +1 -0
  436. package/dist/retention/index.d.ts +50 -0
  437. package/dist/retention/index.d.ts.map +1 -0
  438. package/dist/retention/index.js +50 -0
  439. package/dist/retention/index.js.map +1 -0
  440. package/dist/retention/policy.d.ts +344 -0
  441. package/dist/retention/policy.d.ts.map +1 -0
  442. package/dist/retention/policy.js +472 -0
  443. package/dist/retention/policy.js.map +1 -0
  444. package/dist/retention/purger.d.ts +187 -0
  445. package/dist/retention/purger.d.ts.map +1 -0
  446. package/dist/retention/purger.js +411 -0
  447. package/dist/retention/purger.js.map +1 -0
  448. package/dist/rls/auth-integration.d.ts +280 -0
  449. package/dist/rls/auth-integration.d.ts.map +1 -0
  450. package/dist/rls/auth-integration.js +399 -0
  451. package/dist/rls/auth-integration.js.map +1 -0
  452. package/dist/rls/generator.d.ts +249 -0
  453. package/dist/rls/generator.d.ts.map +1 -0
  454. package/dist/rls/generator.js +495 -0
  455. package/dist/rls/generator.js.map +1 -0
  456. package/dist/rls/index.d.ts +26 -0
  457. package/dist/rls/index.d.ts.map +1 -0
  458. package/dist/rls/index.js +58 -0
  459. package/dist/rls/index.js.map +1 -0
  460. package/dist/rls/policy.d.ts +116 -0
  461. package/dist/rls/policy.d.ts.map +1 -0
  462. package/dist/rls/policy.js +77 -0
  463. package/dist/rls/policy.js.map +1 -0
  464. package/dist/rls/validator.d.ts +155 -0
  465. package/dist/rls/validator.d.ts.map +1 -0
  466. package/dist/rls/validator.js +792 -0
  467. package/dist/rls/validator.js.map +1 -0
  468. package/dist/routing/adaptive-router.d.ts +317 -0
  469. package/dist/routing/adaptive-router.d.ts.map +1 -0
  470. package/dist/routing/adaptive-router.js +554 -0
  471. package/dist/routing/adaptive-router.js.map +1 -0
  472. package/dist/routing/circuit-breaker.d.ts +339 -0
  473. package/dist/routing/circuit-breaker.d.ts.map +1 -0
  474. package/dist/routing/circuit-breaker.js +620 -0
  475. package/dist/routing/circuit-breaker.js.map +1 -0
  476. package/dist/routing/cost-metrics.d.ts +133 -0
  477. package/dist/routing/cost-metrics.d.ts.map +1 -0
  478. package/dist/routing/cost-metrics.js +259 -0
  479. package/dist/routing/cost-metrics.js.map +1 -0
  480. package/dist/routing/do-connection-pool.d.ts +243 -0
  481. package/dist/routing/do-connection-pool.d.ts.map +1 -0
  482. package/dist/routing/do-connection-pool.js +572 -0
  483. package/dist/routing/do-connection-pool.js.map +1 -0
  484. package/dist/routing/index.d.ts +59 -0
  485. package/dist/routing/index.d.ts.map +1 -0
  486. package/dist/routing/index.js +59 -0
  487. package/dist/routing/index.js.map +1 -0
  488. package/dist/routing/query-complexity-estimator.d.ts +73 -0
  489. package/dist/routing/query-complexity-estimator.d.ts.map +1 -0
  490. package/dist/routing/query-complexity-estimator.js +327 -0
  491. package/dist/routing/query-complexity-estimator.js.map +1 -0
  492. package/dist/routing/request-coalescing.d.ts +178 -0
  493. package/dist/routing/request-coalescing.d.ts.map +1 -0
  494. package/dist/routing/request-coalescing.js +325 -0
  495. package/dist/routing/request-coalescing.js.map +1 -0
  496. package/dist/routing/runtime-router.d.ts +107 -0
  497. package/dist/routing/runtime-router.d.ts.map +1 -0
  498. package/dist/routing/runtime-router.js +246 -0
  499. package/dist/routing/runtime-router.js.map +1 -0
  500. package/dist/routing/tenant-router.d.ts +848 -0
  501. package/dist/routing/tenant-router.d.ts.map +1 -0
  502. package/dist/routing/tenant-router.js +1056 -0
  503. package/dist/routing/tenant-router.js.map +1 -0
  504. package/dist/routing/websocket-pool.d.ts +119 -0
  505. package/dist/routing/websocket-pool.d.ts.map +1 -0
  506. package/dist/routing/websocket-pool.js +436 -0
  507. package/dist/routing/websocket-pool.js.map +1 -0
  508. package/dist/storage/cache-layer.d.ts +159 -0
  509. package/dist/storage/cache-layer.d.ts.map +1 -0
  510. package/dist/storage/cache-layer.js +245 -0
  511. package/dist/storage/cache-layer.js.map +1 -0
  512. package/dist/storage/cost-aware-tiering.d.ts +258 -0
  513. package/dist/storage/cost-aware-tiering.d.ts.map +1 -0
  514. package/dist/storage/cost-aware-tiering.js +526 -0
  515. package/dist/storage/cost-aware-tiering.js.map +1 -0
  516. package/dist/storage/index.d.ts +87 -0
  517. package/dist/storage/index.d.ts.map +1 -0
  518. package/dist/storage/index.js +78 -0
  519. package/dist/storage/index.js.map +1 -0
  520. package/dist/storage/interfaces.d.ts +856 -0
  521. package/dist/storage/interfaces.d.ts.map +1 -0
  522. package/dist/storage/interfaces.js +69 -0
  523. package/dist/storage/interfaces.js.map +1 -0
  524. package/dist/storage/r2-layer.d.ts +226 -0
  525. package/dist/storage/r2-layer.d.ts.map +1 -0
  526. package/dist/storage/r2-layer.js +307 -0
  527. package/dist/storage/r2-layer.js.map +1 -0
  528. package/dist/storage/r2-overflow.d.ts +344 -0
  529. package/dist/storage/r2-overflow.d.ts.map +1 -0
  530. package/dist/storage/r2-overflow.js +730 -0
  531. package/dist/storage/r2-overflow.js.map +1 -0
  532. package/dist/storage/r2-page-vfs.d.ts +374 -0
  533. package/dist/storage/r2-page-vfs.d.ts.map +1 -0
  534. package/dist/storage/r2-page-vfs.js +754 -0
  535. package/dist/storage/r2-page-vfs.js.map +1 -0
  536. package/dist/storage/swr-cache.d.ts +181 -0
  537. package/dist/storage/swr-cache.d.ts.map +1 -0
  538. package/dist/storage/swr-cache.js +295 -0
  539. package/dist/storage/swr-cache.js.map +1 -0
  540. package/dist/storage/tiered-orchestrator.d.ts +951 -0
  541. package/dist/storage/tiered-orchestrator.d.ts.map +1 -0
  542. package/dist/storage/tiered-orchestrator.js +1731 -0
  543. package/dist/storage/tiered-orchestrator.js.map +1 -0
  544. package/dist/storage/tiered-vfs-swr.d.ts +279 -0
  545. package/dist/storage/tiered-vfs-swr.d.ts.map +1 -0
  546. package/dist/storage/tiered-vfs-swr.js +584 -0
  547. package/dist/storage/tiered-vfs-swr.js.map +1 -0
  548. package/dist/storage/tiered-vfs.d.ts +405 -0
  549. package/dist/storage/tiered-vfs.d.ts.map +1 -0
  550. package/dist/storage/tiered-vfs.js +833 -0
  551. package/dist/storage/tiered-vfs.js.map +1 -0
  552. package/dist/streaming/backpressure-controller.d.ts +173 -0
  553. package/dist/streaming/backpressure-controller.d.ts.map +1 -0
  554. package/dist/streaming/backpressure-controller.js +344 -0
  555. package/dist/streaming/backpressure-controller.js.map +1 -0
  556. package/dist/streaming/buffer-pool.d.ts +241 -0
  557. package/dist/streaming/buffer-pool.d.ts.map +1 -0
  558. package/dist/streaming/buffer-pool.js +381 -0
  559. package/dist/streaming/buffer-pool.js.map +1 -0
  560. package/dist/streaming/cdc-iceberg-connector.d.ts +272 -0
  561. package/dist/streaming/cdc-iceberg-connector.d.ts.map +1 -0
  562. package/dist/streaming/cdc-iceberg-connector.js +408 -0
  563. package/dist/streaming/cdc-iceberg-connector.js.map +1 -0
  564. package/dist/streaming/index.d.ts +111 -0
  565. package/dist/streaming/index.d.ts.map +1 -0
  566. package/dist/streaming/index.js +128 -0
  567. package/dist/streaming/index.js.map +1 -0
  568. package/dist/streaming/live-cdc-stream.d.ts +400 -0
  569. package/dist/streaming/live-cdc-stream.d.ts.map +1 -0
  570. package/dist/streaming/live-cdc-stream.js +703 -0
  571. package/dist/streaming/live-cdc-stream.js.map +1 -0
  572. package/dist/streaming/memory-bounded-stream.d.ts +207 -0
  573. package/dist/streaming/memory-bounded-stream.d.ts.map +1 -0
  574. package/dist/streaming/memory-bounded-stream.js +340 -0
  575. package/dist/streaming/memory-bounded-stream.js.map +1 -0
  576. package/dist/streaming/query-streamer.d.ts +379 -0
  577. package/dist/streaming/query-streamer.d.ts.map +1 -0
  578. package/dist/streaming/query-streamer.js +495 -0
  579. package/dist/streaming/query-streamer.js.map +1 -0
  580. package/dist/streaming/response-streaming.d.ts +203 -0
  581. package/dist/streaming/response-streaming.d.ts.map +1 -0
  582. package/dist/streaming/response-streaming.js +449 -0
  583. package/dist/streaming/response-streaming.js.map +1 -0
  584. package/dist/types/branded.d.ts +859 -0
  585. package/dist/types/branded.d.ts.map +1 -0
  586. package/dist/types/branded.js +891 -0
  587. package/dist/types/branded.js.map +1 -0
  588. package/dist/types/utilities.d.ts +757 -0
  589. package/dist/types/utilities.d.ts.map +1 -0
  590. package/dist/types/utilities.js +447 -0
  591. package/dist/types/utilities.js.map +1 -0
  592. package/dist/wal/replay-engine.d.ts +344 -0
  593. package/dist/wal/replay-engine.d.ts.map +1 -0
  594. package/dist/wal/replay-engine.js +975 -0
  595. package/dist/wal/replay-engine.js.map +1 -0
  596. package/dist/worker/__mocks__/capnweb.d.ts +13 -0
  597. package/dist/worker/__mocks__/capnweb.d.ts.map +1 -0
  598. package/dist/worker/__mocks__/capnweb.js +15 -0
  599. package/dist/worker/__mocks__/capnweb.js.map +1 -0
  600. package/dist/worker/__mocks__/cloudflare-workers.d.ts +31 -0
  601. package/dist/worker/__mocks__/cloudflare-workers.d.ts.map +1 -0
  602. package/dist/worker/__mocks__/cloudflare-workers.js +33 -0
  603. package/dist/worker/__mocks__/cloudflare-workers.js.map +1 -0
  604. package/dist/worker/__mocks__/pglite.data.d.ts +3 -0
  605. package/dist/worker/__mocks__/pglite.data.d.ts.map +1 -0
  606. package/dist/worker/__mocks__/pglite.data.js +20 -0
  607. package/dist/worker/__mocks__/pglite.data.js.map +1 -0
  608. package/dist/worker/__mocks__/pglite.wasm.d.ts +3 -0
  609. package/dist/worker/__mocks__/pglite.wasm.d.ts.map +1 -0
  610. package/dist/worker/__mocks__/pglite.wasm.js +30 -0
  611. package/dist/worker/__mocks__/pglite.wasm.js.map +1 -0
  612. package/dist/worker/auth-rate-limiter.d.ts +270 -0
  613. package/dist/worker/auth-rate-limiter.d.ts.map +1 -0
  614. package/dist/worker/auth-rate-limiter.js +332 -0
  615. package/dist/worker/auth-rate-limiter.js.map +1 -0
  616. package/dist/worker/auth.d.ts +345 -0
  617. package/dist/worker/auth.d.ts.map +1 -0
  618. package/dist/worker/auth.js +837 -0
  619. package/dist/worker/auth.js.map +1 -0
  620. package/dist/worker/cdc-backpressure.d.ts +338 -0
  621. package/dist/worker/cdc-backpressure.d.ts.map +1 -0
  622. package/dist/worker/cdc-backpressure.js +619 -0
  623. package/dist/worker/cdc-backpressure.js.map +1 -0
  624. package/dist/worker/cdc-sse.d.ts +277 -0
  625. package/dist/worker/cdc-sse.d.ts.map +1 -0
  626. package/dist/worker/cdc-sse.js +528 -0
  627. package/dist/worker/cdc-sse.js.map +1 -0
  628. package/dist/worker/cdc-websocket.d.ts +252 -0
  629. package/dist/worker/cdc-websocket.d.ts.map +1 -0
  630. package/dist/worker/cdc-websocket.js +940 -0
  631. package/dist/worker/cdc-websocket.js.map +1 -0
  632. package/dist/worker/cdc.d.ts +95 -0
  633. package/dist/worker/cdc.d.ts.map +1 -0
  634. package/dist/worker/cdc.js +211 -0
  635. package/dist/worker/cdc.js.map +1 -0
  636. package/dist/worker/concerns/auth-concern.d.ts +50 -0
  637. package/dist/worker/concerns/auth-concern.d.ts.map +1 -0
  638. package/dist/worker/concerns/auth-concern.js +131 -0
  639. package/dist/worker/concerns/auth-concern.js.map +1 -0
  640. package/dist/worker/concerns/cdc-concern.d.ts +99 -0
  641. package/dist/worker/concerns/cdc-concern.d.ts.map +1 -0
  642. package/dist/worker/concerns/cdc-concern.js +137 -0
  643. package/dist/worker/concerns/cdc-concern.js.map +1 -0
  644. package/dist/worker/concerns/index.d.ts +22 -0
  645. package/dist/worker/concerns/index.d.ts.map +1 -0
  646. package/dist/worker/concerns/index.js +13 -0
  647. package/dist/worker/concerns/index.js.map +1 -0
  648. package/dist/worker/concerns/query-execution-concern.d.ts +104 -0
  649. package/dist/worker/concerns/query-execution-concern.d.ts.map +1 -0
  650. package/dist/worker/concerns/query-execution-concern.js +95 -0
  651. package/dist/worker/concerns/query-execution-concern.js.map +1 -0
  652. package/dist/worker/concerns/storage-orchestration-concern.d.ts +78 -0
  653. package/dist/worker/concerns/storage-orchestration-concern.d.ts.map +1 -0
  654. package/dist/worker/concerns/storage-orchestration-concern.js +240 -0
  655. package/dist/worker/concerns/storage-orchestration-concern.js.map +1 -0
  656. package/dist/worker/do-auth-manager.d.ts +108 -0
  657. package/dist/worker/do-auth-manager.d.ts.map +1 -0
  658. package/dist/worker/do-auth-manager.js +212 -0
  659. package/dist/worker/do-auth-manager.js.map +1 -0
  660. package/dist/worker/do-pglite-manager.d.ts +137 -0
  661. package/dist/worker/do-pglite-manager.d.ts.map +1 -0
  662. package/dist/worker/do-pglite-manager.js +228 -0
  663. package/dist/worker/do-pglite-manager.js.map +1 -0
  664. package/dist/worker/do.d.ts +556 -0
  665. package/dist/worker/do.d.ts.map +1 -0
  666. package/dist/worker/do.js +1441 -0
  667. package/dist/worker/do.js.map +1 -0
  668. package/dist/worker/entry.d.ts +23 -0
  669. package/dist/worker/entry.d.ts.map +1 -0
  670. package/dist/worker/entry.js +362 -0
  671. package/dist/worker/entry.js.map +1 -0
  672. package/dist/worker/errors.d.ts +106 -0
  673. package/dist/worker/errors.d.ts.map +1 -0
  674. package/dist/worker/errors.js +178 -0
  675. package/dist/worker/errors.js.map +1 -0
  676. package/dist/worker/health-check-manager.d.ts +141 -0
  677. package/dist/worker/health-check-manager.d.ts.map +1 -0
  678. package/dist/worker/health-check-manager.js +145 -0
  679. package/dist/worker/health-check-manager.js.map +1 -0
  680. package/dist/worker/index.d.ts +60 -0
  681. package/dist/worker/index.d.ts.map +1 -0
  682. package/dist/worker/index.js +67 -0
  683. package/dist/worker/index.js.map +1 -0
  684. package/dist/worker/memory-pressure.d.ts +892 -0
  685. package/dist/worker/memory-pressure.d.ts.map +1 -0
  686. package/dist/worker/memory-pressure.js +1990 -0
  687. package/dist/worker/memory-pressure.js.map +1 -0
  688. package/dist/worker/migration-manager.d.ts +153 -0
  689. package/dist/worker/migration-manager.d.ts.map +1 -0
  690. package/dist/worker/migration-manager.js +461 -0
  691. package/dist/worker/migration-manager.js.map +1 -0
  692. package/dist/worker/plugin-manager.d.ts +147 -0
  693. package/dist/worker/plugin-manager.d.ts.map +1 -0
  694. package/dist/worker/plugin-manager.js +408 -0
  695. package/dist/worker/plugin-manager.js.map +1 -0
  696. package/dist/worker/proxy.d.ts +330 -0
  697. package/dist/worker/proxy.d.ts.map +1 -0
  698. package/dist/worker/proxy.js +504 -0
  699. package/dist/worker/proxy.js.map +1 -0
  700. package/dist/worker/query-execution-manager.d.ts +107 -0
  701. package/dist/worker/query-execution-manager.d.ts.map +1 -0
  702. package/dist/worker/query-execution-manager.js +155 -0
  703. package/dist/worker/query-execution-manager.js.map +1 -0
  704. package/dist/worker/query-executor.d.ts +163 -0
  705. package/dist/worker/query-executor.d.ts.map +1 -0
  706. package/dist/worker/query-executor.js +413 -0
  707. package/dist/worker/query-executor.js.map +1 -0
  708. package/dist/worker/query-stats-manager.d.ts +117 -0
  709. package/dist/worker/query-stats-manager.d.ts.map +1 -0
  710. package/dist/worker/query-stats-manager.js +162 -0
  711. package/dist/worker/query-stats-manager.js.map +1 -0
  712. package/dist/worker/result-handler.d.ts +192 -0
  713. package/dist/worker/result-handler.d.ts.map +1 -0
  714. package/dist/worker/result-handler.js +346 -0
  715. package/dist/worker/result-handler.js.map +1 -0
  716. package/dist/worker/routes.d.ts +135 -0
  717. package/dist/worker/routes.d.ts.map +1 -0
  718. package/dist/worker/routes.js +460 -0
  719. package/dist/worker/routes.js.map +1 -0
  720. package/dist/worker/rpc-methods-manager.d.ts +142 -0
  721. package/dist/worker/rpc-methods-manager.d.ts.map +1 -0
  722. package/dist/worker/rpc-methods-manager.js +195 -0
  723. package/dist/worker/rpc-methods-manager.js.map +1 -0
  724. package/dist/worker/rpc.d.ts +259 -0
  725. package/dist/worker/rpc.d.ts.map +1 -0
  726. package/dist/worker/rpc.js +398 -0
  727. package/dist/worker/rpc.js.map +1 -0
  728. package/dist/worker/schema-version.d.ts +209 -0
  729. package/dist/worker/schema-version.d.ts.map +1 -0
  730. package/dist/worker/schema-version.js +450 -0
  731. package/dist/worker/schema-version.js.map +1 -0
  732. package/dist/worker/session-manager.d.ts +282 -0
  733. package/dist/worker/session-manager.d.ts.map +1 -0
  734. package/dist/worker/session-manager.js +523 -0
  735. package/dist/worker/session-manager.js.map +1 -0
  736. package/dist/worker/shutdown-manager.d.ts +188 -0
  737. package/dist/worker/shutdown-manager.d.ts.map +1 -0
  738. package/dist/worker/shutdown-manager.js +347 -0
  739. package/dist/worker/shutdown-manager.js.map +1 -0
  740. package/dist/worker/sql-transform.d.ts +61 -0
  741. package/dist/worker/sql-transform.d.ts.map +1 -0
  742. package/dist/worker/sql-transform.js +312 -0
  743. package/dist/worker/sql-transform.js.map +1 -0
  744. package/dist/worker/types.d.ts +738 -0
  745. package/dist/worker/types.d.ts.map +1 -0
  746. package/dist/worker/types.js +6 -0
  747. package/dist/worker/types.js.map +1 -0
  748. package/dist/worker/user-routes.d.ts +76 -0
  749. package/dist/worker/user-routes.d.ts.map +1 -0
  750. package/dist/worker/user-routes.js +188 -0
  751. package/dist/worker/user-routes.js.map +1 -0
  752. package/dist/worker/wal-facade.d.ts +138 -0
  753. package/dist/worker/wal-facade.d.ts.map +1 -0
  754. package/dist/worker/wal-facade.js +184 -0
  755. package/dist/worker/wal-facade.js.map +1 -0
  756. package/dist/worker/wal-r2.d.ts +271 -0
  757. package/dist/worker/wal-r2.d.ts.map +1 -0
  758. package/dist/worker/wal-r2.js +689 -0
  759. package/dist/worker/wal-r2.js.map +1 -0
  760. package/dist/worker/wal-replay.d.ts +361 -0
  761. package/dist/worker/wal-replay.d.ts.map +1 -0
  762. package/dist/worker/wal-replay.js +628 -0
  763. package/dist/worker/wal-replay.js.map +1 -0
  764. package/dist/worker/wal-retention.d.ts +389 -0
  765. package/dist/worker/wal-retention.d.ts.map +1 -0
  766. package/dist/worker/wal-retention.js +763 -0
  767. package/dist/worker/wal-retention.js.map +1 -0
  768. package/dist/worker/wal.d.ts +278 -0
  769. package/dist/worker/wal.d.ts.map +1 -0
  770. package/dist/worker/wal.js +467 -0
  771. package/dist/worker/wal.js.map +1 -0
  772. package/dist/worker/websocket.d.ts +85 -0
  773. package/dist/worker/websocket.d.ts.map +1 -0
  774. package/dist/worker/websocket.js +227 -0
  775. package/dist/worker/websocket.js.map +1 -0
  776. package/package.json +108 -0
  777. package/src/cdc/change-stream.ts +137 -0
  778. package/src/cdc/filter.ts +646 -0
  779. package/src/cdc/index.ts +112 -0
  780. package/src/cdc/resume-token.ts +280 -0
  781. package/src/cdc/transport/index.ts +7 -0
  782. package/src/cdc/transport/sse.ts +723 -0
  783. package/src/cdc/transport/websocket.ts +873 -0
  784. package/src/cdc/types.ts +346 -0
  785. package/src/config/index.ts +25 -0
  786. package/src/config/memory.ts +177 -0
  787. package/src/config/storage.ts +204 -0
  788. package/src/config/streaming.ts +147 -0
  789. package/src/config/timeouts.ts +221 -0
  790. package/src/extensions/config.test.ts +187 -0
  791. package/src/extensions/config.ts +278 -0
  792. package/src/extensions/geo.test.ts +455 -0
  793. package/src/extensions/geo.ts +858 -0
  794. package/src/extensions/index.test.ts +259 -0
  795. package/src/extensions/index.ts +227 -0
  796. package/src/extensions/loader.test.ts +555 -0
  797. package/src/extensions/loader.ts +588 -0
  798. package/src/extensions/pgmq-lite.test.ts +727 -0
  799. package/src/extensions/pgmq-lite.ts +770 -0
  800. package/src/extensions/plugins.test.ts +528 -0
  801. package/src/extensions/plugins.ts +718 -0
  802. package/src/extensions/registry.test.ts +202 -0
  803. package/src/extensions/registry.ts +267 -0
  804. package/src/extensions/vector.test.ts +195 -0
  805. package/src/extensions/vector.ts +217 -0
  806. package/src/iceberg/SCHEDULER.md +580 -0
  807. package/src/iceberg/analytics.test.ts +703 -0
  808. package/src/iceberg/analytics.ts +727 -0
  809. package/src/iceberg/catalog-api.test.ts +838 -0
  810. package/src/iceberg/catalog-api.ts +520 -0
  811. package/src/iceberg/catalog.test.ts +680 -0
  812. package/src/iceberg/catalog.ts +1007 -0
  813. package/src/iceberg/iceberg.test.ts +705 -0
  814. package/src/iceberg/index.ts +406 -0
  815. package/src/iceberg/metadata.test.ts +632 -0
  816. package/src/iceberg/metadata.ts +649 -0
  817. package/src/iceberg/optimizer.test.ts +868 -0
  818. package/src/iceberg/optimizer.ts +1287 -0
  819. package/src/iceberg/parquet.test.ts +899 -0
  820. package/src/iceberg/parquet.ts +1640 -0
  821. package/src/iceberg/r2-organization.test.ts +615 -0
  822. package/src/iceberg/r2-organization.ts +951 -0
  823. package/src/iceberg/scheduler-do-example.ts +364 -0
  824. package/src/iceberg/scheduler.test.ts +861 -0
  825. package/src/iceberg/scheduler.ts +1201 -0
  826. package/src/iceberg/schema.test.ts +547 -0
  827. package/src/iceberg/schema.ts +616 -0
  828. package/src/iceberg/snapshot-manager.test.ts +919 -0
  829. package/src/iceberg/snapshot-manager.ts +1369 -0
  830. package/src/iceberg/sql-router.test.ts +334 -0
  831. package/src/iceberg/sql-router.ts +337 -0
  832. package/src/iceberg/test-fixtures.ts +605 -0
  833. package/src/iceberg/time-travel-api.test.ts +1029 -0
  834. package/src/iceberg/time-travel-api.ts +731 -0
  835. package/src/iceberg/time-travel.test.ts +1218 -0
  836. package/src/iceberg/time-travel.ts +1052 -0
  837. package/src/iceberg/transformer.test.ts +689 -0
  838. package/src/iceberg/transformer.ts +1029 -0
  839. package/src/iceberg/types.ts +373 -0
  840. package/src/iceberg/writer.test.ts +716 -0
  841. package/src/iceberg/writer.ts +590 -0
  842. package/src/index.ts +212 -0
  843. package/src/lineage/index.ts +42 -0
  844. package/src/lineage/integration.ts +334 -0
  845. package/src/lineage/tracker.ts +1618 -0
  846. package/src/lineage/types.ts +354 -0
  847. package/src/middleware/index.ts +36 -0
  848. package/src/middleware/rate-limit-concurrent.test.ts +794 -0
  849. package/src/middleware/rate-limit.test.ts +1568 -0
  850. package/src/middleware/rate-limit.ts +840 -0
  851. package/src/migration-tooling/external-migration.test.ts +1864 -0
  852. package/src/migration-tooling/external-migration.ts +2355 -0
  853. package/src/migration-tooling/index.ts +19 -0
  854. package/src/migrations/ARCHITECTURE.md +474 -0
  855. package/src/migrations/PROGRESS_TRACKING.md +485 -0
  856. package/src/migrations/auto-migrator.test.ts +732 -0
  857. package/src/migrations/auto-migrator.ts +531 -0
  858. package/src/migrations/bulk-orchestrator.test.ts +801 -0
  859. package/src/migrations/bulk-orchestrator.ts +1039 -0
  860. package/src/migrations/compatibility.test.ts +958 -0
  861. package/src/migrations/compatibility.ts +902 -0
  862. package/src/migrations/do-migrations.test.ts +2620 -0
  863. package/src/migrations/do-migrations.ts +1289 -0
  864. package/src/migrations/do-migrations.types.ts +715 -0
  865. package/src/migrations/drizzle-compat.test.ts +210 -0
  866. package/src/migrations/drizzle-compat.ts +337 -0
  867. package/src/migrations/index.ts +334 -0
  868. package/src/migrations/migration-api.test.ts +438 -0
  869. package/src/migrations/migration-api.ts +704 -0
  870. package/src/migrations/progress-tracker-do.ts +518 -0
  871. package/src/migrations/progress-tracker-kv.ts +305 -0
  872. package/src/migrations/progress-tracker.test.ts +937 -0
  873. package/src/migrations/progress-tracker.ts +665 -0
  874. package/src/migrations/registry.test.ts +331 -0
  875. package/src/migrations/registry.ts +468 -0
  876. package/src/migrations/rollback.test.ts +644 -0
  877. package/src/migrations/runner.test.ts +807 -0
  878. package/src/migrations/runner.test.ts.backup +759 -0
  879. package/src/migrations/runner.ts +1459 -0
  880. package/src/migrations/schema-generator.test.ts +649 -0
  881. package/src/migrations/schema-generator.ts +513 -0
  882. package/src/migrations/testing.ts +1037 -0
  883. package/src/migrations/types.ts +573 -0
  884. package/src/migrations/validator.test.ts +660 -0
  885. package/src/migrations/validator.ts +741 -0
  886. package/src/observability/alerting.test.ts +1133 -0
  887. package/src/observability/alerting.ts +455 -0
  888. package/src/observability/analytics-engine.ts +733 -0
  889. package/src/observability/cost-metrics.ts +804 -0
  890. package/src/observability/cross-do-tracing.test.ts +516 -0
  891. package/src/observability/cross-do-tracing.ts +588 -0
  892. package/src/observability/dashboards/postgres-do-overview.json +1656 -0
  893. package/src/observability/error-rate-collector.test.ts +977 -0
  894. package/src/observability/error-rate-collector.ts +518 -0
  895. package/src/observability/exporters.test.ts +365 -0
  896. package/src/observability/exporters.ts +650 -0
  897. package/src/observability/health-check.test.ts +353 -0
  898. package/src/observability/health-check.ts +341 -0
  899. package/src/observability/index.test.ts +298 -0
  900. package/src/observability/index.ts +885 -0
  901. package/src/observability/instrumentation.test.ts +428 -0
  902. package/src/observability/instrumentation.ts +788 -0
  903. package/src/observability/memory-metrics.test.ts +355 -0
  904. package/src/observability/memory-metrics.ts +990 -0
  905. package/src/observability/metrics-endpoint.test.ts +402 -0
  906. package/src/observability/metrics-endpoint.ts +374 -0
  907. package/src/observability/metrics.test.ts +291 -0
  908. package/src/observability/metrics.ts +315 -0
  909. package/src/observability/observability-features.ts +1296 -0
  910. package/src/observability/prometheus.test.ts +292 -0
  911. package/src/observability/prometheus.ts +170 -0
  912. package/src/observability/propagation.test.ts +417 -0
  913. package/src/observability/propagation.ts +294 -0
  914. package/src/observability/query-latency.ts +586 -0
  915. package/src/observability/query-performance.test.ts +406 -0
  916. package/src/observability/query-performance.ts +491 -0
  917. package/src/observability/storage-tier-metrics.test.ts +633 -0
  918. package/src/observability/storage-tier-metrics.ts +570 -0
  919. package/src/observability/tier-cost-optimizer.ts +740 -0
  920. package/src/observability/tracer.test.ts +346 -0
  921. package/src/observability/tracer.ts +585 -0
  922. package/src/observability/types.test.ts +726 -0
  923. package/src/observability/types.ts +434 -0
  924. package/src/pglite/auto-demotion.test.ts +477 -0
  925. package/src/pglite/auto-demotion.ts +385 -0
  926. package/src/pglite/auto-promotion.test.ts +824 -0
  927. package/src/pglite/auto-promotion.ts +547 -0
  928. package/src/pglite/cache-layer.test.ts +469 -0
  929. package/src/pglite/cache-layer.ts +271 -0
  930. package/src/pglite/cold-start-manager.ts +1260 -0
  931. package/src/pglite/cold-start-optimizer.test.ts +937 -0
  932. package/src/pglite/cold-start-optimizer.ts +1895 -0
  933. package/src/pglite/dovfs-adapter.ts +1122 -0
  934. package/src/pglite/dovfs.ts +1258 -0
  935. package/src/pglite/etag-cache.test.ts +844 -0
  936. package/src/pglite/etag-cache.ts +526 -0
  937. package/src/pglite/index.ts +442 -0
  938. package/src/pglite/init.test.ts +455 -0
  939. package/src/pglite/init.ts +574 -0
  940. package/src/pglite/lifecycle.test.ts +599 -0
  941. package/src/pglite/lifecycle.ts +704 -0
  942. package/src/pglite/parallel-loader.test.ts +586 -0
  943. package/src/pglite/parallel-loader.ts +481 -0
  944. package/src/pglite/production-pglite.test.ts +666 -0
  945. package/src/pglite/production-pglite.ts +537 -0
  946. package/src/pglite/query-executor.ts +614 -0
  947. package/src/pglite/r2-layer.test.ts +501 -0
  948. package/src/pglite/r2-layer.ts +322 -0
  949. package/src/pglite/tiered-init.test.ts +725 -0
  950. package/src/pglite/tiered-init.ts +556 -0
  951. package/src/pglite/tiered-vfs.test.ts +726 -0
  952. package/src/pglite/tiered-vfs.ts +33 -0
  953. package/src/pglite/tiering-stats.test.ts +531 -0
  954. package/src/pglite/tiering-stats.ts +407 -0
  955. package/src/pglite/transaction-hooks.ts +343 -0
  956. package/src/pglite/warm-loader.test.ts +1701 -0
  957. package/src/pglite/warm-loader.ts +528 -0
  958. package/src/pglite/workers-pglite.ts +224 -0
  959. package/src/pglite-assets/pglite.data +0 -0
  960. package/src/pglite-assets/pglite.wasm +0 -0
  961. package/src/pglite.d.ts +47 -0
  962. package/src/playground/index.ts +137 -0
  963. package/src/playground/keyboard-shortcuts.ts +677 -0
  964. package/src/playground/playground.ts +323 -0
  965. package/src/playground/query-executor.ts +669 -0
  966. package/src/playground/query-history.ts +328 -0
  967. package/src/playground/result-formatter.ts +420 -0
  968. package/src/playground/sample-datasets.ts +674 -0
  969. package/src/playground/sample-queries.ts +1168 -0
  970. package/src/playground/schema-explorer.ts +558 -0
  971. package/src/playground/types.ts +518 -0
  972. package/src/readonly/cache-reader.test.ts +460 -0
  973. package/src/readonly/cache-reader.ts +313 -0
  974. package/src/readonly/config.test.ts +187 -0
  975. package/src/readonly/config.ts +128 -0
  976. package/src/readonly/index.ts +50 -0
  977. package/src/readonly/pglite-wrapper.test.ts +278 -0
  978. package/src/readonly/pglite-wrapper.ts +184 -0
  979. package/src/readonly/worker.test.ts +533 -0
  980. package/src/readonly/worker.ts +341 -0
  981. package/src/readonly/write-blocker.test.ts +459 -0
  982. package/src/readonly/write-blocker.ts +175 -0
  983. package/src/recovery/disaster-recovery.test.ts +618 -0
  984. package/src/recovery/disaster-recovery.ts +1181 -0
  985. package/src/recovery/index.ts +43 -0
  986. package/src/recovery/parquet-parser.ts +974 -0
  987. package/src/retention/index.ts +74 -0
  988. package/src/retention/policy.test.ts +571 -0
  989. package/src/retention/policy.ts +774 -0
  990. package/src/retention/purger.test.ts +465 -0
  991. package/src/retention/purger.ts +558 -0
  992. package/src/rls/auth-integration.test.ts +752 -0
  993. package/src/rls/auth-integration.ts +533 -0
  994. package/src/rls/generator.test.ts +829 -0
  995. package/src/rls/generator.ts +573 -0
  996. package/src/rls/index.ts +128 -0
  997. package/src/rls/policy.ts +208 -0
  998. package/src/rls/rls.test.ts +1071 -0
  999. package/src/rls/validator.test.ts +930 -0
  1000. package/src/rls/validator.ts +895 -0
  1001. package/src/routing/adaptive-router.test.ts +884 -0
  1002. package/src/routing/adaptive-router.ts +845 -0
  1003. package/src/routing/circuit-breaker.test.ts +1505 -0
  1004. package/src/routing/circuit-breaker.ts +852 -0
  1005. package/src/routing/cost-metrics.test.ts +565 -0
  1006. package/src/routing/cost-metrics.ts +408 -0
  1007. package/src/routing/do-connection-pool.test.ts +1109 -0
  1008. package/src/routing/do-connection-pool.ts +828 -0
  1009. package/src/routing/index.ts +158 -0
  1010. package/src/routing/query-complexity-estimator.test.ts +356 -0
  1011. package/src/routing/query-complexity-estimator.ts +444 -0
  1012. package/src/routing/request-coalescing.test.ts +738 -0
  1013. package/src/routing/request-coalescing.ts +475 -0
  1014. package/src/routing/runtime-router.test.ts +436 -0
  1015. package/src/routing/runtime-router.ts +357 -0
  1016. package/src/routing/tenant-router.test.ts +2493 -0
  1017. package/src/routing/tenant-router.ts +1908 -0
  1018. package/src/routing/websocket-pool.test.ts +551 -0
  1019. package/src/routing/websocket-pool.ts +577 -0
  1020. package/src/storage/access-pattern-tracker.test.ts +874 -0
  1021. package/src/storage/cache-layer.test.ts +560 -0
  1022. package/src/storage/cache-layer.ts +328 -0
  1023. package/src/storage/cost-aware-tiering.test.ts +652 -0
  1024. package/src/storage/cost-aware-tiering.ts +794 -0
  1025. package/src/storage/do-sqlite-blobs.test.ts +937 -0
  1026. package/src/storage/index.ts +272 -0
  1027. package/src/storage/interfaces.ts +974 -0
  1028. package/src/storage/r2-layer.test.ts +653 -0
  1029. package/src/storage/r2-layer.ts +434 -0
  1030. package/src/storage/r2-overflow.ts +920 -0
  1031. package/src/storage/r2-page-vfs.test.ts +2348 -0
  1032. package/src/storage/r2-page-vfs.ts +1054 -0
  1033. package/src/storage/swr-cache.test.ts +832 -0
  1034. package/src/storage/swr-cache.ts +398 -0
  1035. package/src/storage/swr-tiered-integration.test.ts +617 -0
  1036. package/src/storage/tiered-orchestrator.test.ts +2441 -0
  1037. package/src/storage/tiered-orchestrator.ts +2081 -0
  1038. package/src/storage/tiered-vfs-swr.test.ts +736 -0
  1039. package/src/storage/tiered-vfs-swr.ts +735 -0
  1040. package/src/storage/tiered-vfs.test.ts +793 -0
  1041. package/src/storage/tiered-vfs.ts +1082 -0
  1042. package/src/streaming/backpressure-controller.ts +452 -0
  1043. package/src/streaming/buffer-pool.ts +484 -0
  1044. package/src/streaming/cdc-iceberg-connector.ts +605 -0
  1045. package/src/streaming/index.ts +225 -0
  1046. package/src/streaming/live-cdc-stream.ts +985 -0
  1047. package/src/streaming/memory-bounded-stream.ts +443 -0
  1048. package/src/streaming/query-streamer.ts +662 -0
  1049. package/src/streaming/response-streaming.ts +557 -0
  1050. package/src/types/branded.ts +1075 -0
  1051. package/src/types/branded.ts.backup +273 -0
  1052. package/src/types/utilities.ts +1023 -0
  1053. package/src/types/wasm.d.ts +30 -0
  1054. package/src/validation/typed-errors.test.ts +420 -0
  1055. package/src/wal/replay-engine.ts +1264 -0
  1056. package/src/worker/__mocks__/capnweb.ts +15 -0
  1057. package/src/worker/__mocks__/pglite.data.ts +22 -0
  1058. package/src/worker/__mocks__/pglite.wasm.ts +33 -0
  1059. package/src/worker/auth-rate-limiter.test.ts +272 -0
  1060. package/src/worker/auth-rate-limiter.ts +448 -0
  1061. package/src/worker/auth.security-red.test.ts +1236 -0
  1062. package/src/worker/auth.security.test.ts +822 -0
  1063. package/src/worker/auth.test.ts +469 -0
  1064. package/src/worker/auth.ts +1104 -0
  1065. package/src/worker/cdc-backpressure.test.ts +726 -0
  1066. package/src/worker/cdc-backpressure.ts +866 -0
  1067. package/src/worker/cdc-sse.test.ts +780 -0
  1068. package/src/worker/cdc-sse.ts +728 -0
  1069. package/src/worker/cdc-websocket.ts +1229 -0
  1070. package/src/worker/cdc-ws.test.ts +1009 -0
  1071. package/src/worker/cdc.test.ts +327 -0
  1072. package/src/worker/cdc.ts +289 -0
  1073. package/src/worker/concerns/auth-concern.ts +179 -0
  1074. package/src/worker/concerns/cdc-concern.ts +247 -0
  1075. package/src/worker/concerns/index.ts +58 -0
  1076. package/src/worker/concerns/query-execution-concern.ts +194 -0
  1077. package/src/worker/concerns/storage-orchestration-concern.ts +373 -0
  1078. package/src/worker/discriminated-types.test.ts +280 -0
  1079. package/src/worker/do-auth-manager.ts +257 -0
  1080. package/src/worker/do-decomposition.test.ts +1236 -0
  1081. package/src/worker/do-pglite-manager.ts +302 -0
  1082. package/src/worker/do.test.ts +2254 -0
  1083. package/src/worker/do.ts +1878 -0
  1084. package/src/worker/entry.ts +417 -0
  1085. package/src/worker/errors.ts +285 -0
  1086. package/src/worker/health-check-manager.test.ts +261 -0
  1087. package/src/worker/health-check-manager.ts +231 -0
  1088. package/src/worker/index.ts +389 -0
  1089. package/src/worker/memory-pressure.test.ts +1460 -0
  1090. package/src/worker/memory-pressure.ts +2650 -0
  1091. package/src/worker/migration-manager.ts +582 -0
  1092. package/src/worker/neon-compat.test.ts +332 -0
  1093. package/src/worker/plugin-manager.ts +485 -0
  1094. package/src/worker/postgres.do-rpc.d.ts +76 -0
  1095. package/src/worker/proxy.ts +694 -0
  1096. package/src/worker/query-execution-manager.test.ts +303 -0
  1097. package/src/worker/query-execution-manager.ts +219 -0
  1098. package/src/worker/query-executor.test.ts +282 -0
  1099. package/src/worker/query-executor.ts +560 -0
  1100. package/src/worker/query-stats-manager.ts +229 -0
  1101. package/src/worker/result-handler.test.ts +364 -0
  1102. package/src/worker/result-handler.ts +510 -0
  1103. package/src/worker/routes.test.ts +795 -0
  1104. package/src/worker/routes.ts +650 -0
  1105. package/src/worker/rpc-methods-manager.test.ts +326 -0
  1106. package/src/worker/rpc-methods-manager.ts +276 -0
  1107. package/src/worker/rpc.ts +524 -0
  1108. package/src/worker/schema-version.ts +605 -0
  1109. package/src/worker/session-manager.test.ts +506 -0
  1110. package/src/worker/session-manager.ts +732 -0
  1111. package/src/worker/shutdown-manager.ts +469 -0
  1112. package/src/worker/sql-transform.test.ts +286 -0
  1113. package/src/worker/sql-transform.ts +368 -0
  1114. package/src/worker/supabase-compat.test.ts +621 -0
  1115. package/src/worker/types.test.ts +292 -0
  1116. package/src/worker/types.ts +873 -0
  1117. package/src/worker/user-routes.test.ts +703 -0
  1118. package/src/worker/user-routes.ts +303 -0
  1119. package/src/worker/wal-facade.ts +235 -0
  1120. package/src/worker/wal-r2.test.ts +570 -0
  1121. package/src/worker/wal-r2.ts +930 -0
  1122. package/src/worker/wal-replay.test.ts +845 -0
  1123. package/src/worker/wal-replay.ts +897 -0
  1124. package/src/worker/wal-retention.test.ts +758 -0
  1125. package/src/worker/wal-retention.ts +1075 -0
  1126. package/src/worker/wal.test.ts +618 -0
  1127. package/src/worker/wal.ts +697 -0
  1128. package/src/worker/websocket.test.ts +296 -0
  1129. package/src/worker/websocket.ts +284 -0
@@ -0,0 +1,1731 @@
1
+ /**
2
+ * TieredStorageOrchestrator - Unified Tiering System
3
+ *
4
+ * Orchestrates the complete tiered storage system with:
5
+ * - HOT tier: Cloudflare Cache API (FREE, sync-fast)
6
+ * - WARM tier: Durable Object SQLite blobs (persistent, sync)
7
+ * - COLD tier: R2 object storage (cheap, async)
8
+ *
9
+ * ## Features
10
+ * - Unified read/write interface across all tiers
11
+ * - Automatic promotion based on access patterns
12
+ * - Automatic demotion based on TTL/LRU policies
13
+ * - Cost-optimized tier selection
14
+ * - Comprehensive statistics and monitoring
15
+ * - Storage index for fast tier location lookups
16
+ * - DO lifecycle hooks (hibernate/wake)
17
+ * - Circuit breaker pattern for tier failures
18
+ * - Integrated metrics aggregation
19
+ * - Bounded storage index with LRU/LFU eviction
20
+ * - Detailed performance metrics and memory tracking
21
+ *
22
+ * ## Performance Characteristics
23
+ *
24
+ * ### Storage Index Operations
25
+ *
26
+ * | Operation | Time Complexity | Typical Latency |
27
+ * |---------------|-----------------|-----------------|
28
+ * | Lookup (get) | O(1) average | 50-100ns |
29
+ * | Update (set) | O(1) amortized | 100-200ns |
30
+ * | Delete | O(1) | 50-100ns |
31
+ * | Eviction | O(n*k) | 1-10ms/batch |
32
+ * | Maintenance | O(n * storage) | 100ms-10s |
33
+ *
34
+ * Where:
35
+ * - n = total index entries
36
+ * - k = eviction batch size (typically 10-20)
37
+ *
38
+ * ### Memory Usage
39
+ *
40
+ * The storage index uses approximately:
41
+ * - 120 bytes per entry (base overhead)
42
+ * - 2 bytes per character in key (JS UTF-16 strings)
43
+ * - ~10% additional for Map internal structures
44
+ *
45
+ * **Example Memory Usage:**
46
+ * | Entries | Avg Key Length | Estimated Memory |
47
+ * |---------|----------------|------------------|
48
+ * | 1,000 | 20 chars | ~160 KB |
49
+ * | 10,000 | 20 chars | ~1.6 MB |
50
+ * | 100,000 | 20 chars | ~16 MB |
51
+ * | 10,000 | 100 chars | ~3.2 MB |
52
+ *
53
+ * ### Eviction Policies
54
+ *
55
+ * - **LRU (default)**: Evicts least recently accessed entries first.
56
+ * Best for: Most workloads with temporal locality.
57
+ *
58
+ * - **LFU**: Evicts least frequently accessed entries first.
59
+ * Best for: Workloads with stable hot sets.
60
+ *
61
+ * - **FIFO**: Evicts oldest entries by creation time.
62
+ * Best for: Predictable eviction patterns, debugging.
63
+ *
64
+ * ### Hot Path Optimizations
65
+ *
66
+ * 1. **Single-entry lookup cache**: Avoids redundant Map lookups when
67
+ * the same key is accessed multiple times in quick succession
68
+ * (e.g., read -> check promotion -> update index).
69
+ *
70
+ * 2. **Partial selection for eviction**: Uses O(n*k) partial selection
71
+ * instead of O(n log n) full sort when evicting k entries from n.
72
+ *
73
+ * 3. **Batch eviction**: Amortizes eviction overhead across multiple
74
+ * entries (configurable via indexEvictionBatchSize).
75
+ *
76
+ * ### Configuration Guidelines
77
+ *
78
+ * For Cloudflare Workers (128MB limit):
79
+ * ```typescript
80
+ * const orchestrator = createTieredStorageOrchestrator({
81
+ * // ... other config
82
+ * maxIndexEntries: 50000, // ~8MB for 20-char keys
83
+ * maxIndexMemoryBytes: 8 * 1024 * 1024, // 8MB hard limit
84
+ * indexEvictionPolicy: 'lru',
85
+ * indexEvictionBatchSize: 100, // Evict 100 at a time
86
+ * indexMemoryWarningThreshold: 0.8, // Warn at 80%
87
+ * })
88
+ * ```
89
+ *
90
+ * @module storage/tiered-orchestrator
91
+ */
92
+ // =============================================================================
93
+ // Imported Configuration Constants (from centralized config)
94
+ // =============================================================================
95
+ import { DEFAULT_PAGE_SIZE, DEFAULT_COLD_TO_WARM_THRESHOLD, DEFAULT_WARM_TO_HOT_THRESHOLD, DEFAULT_PROMOTION_WINDOW_MS, DEFAULT_HOT_TTL_MS, DEFAULT_WARM_TTL_MS, DEFAULT_MAX_HOT_PAGES, DEFAULT_DO_PREFIX, DEFAULT_INDEX_EVICTION_BATCH_SIZE, DEFAULT_CIRCUIT_BREAKER_FAILURE_THRESHOLD, DEFAULT_CIRCUIT_BREAKER_RESET_TIMEOUT_MS, } from '../config/storage';
96
+ import { INDEX_ENTRY_MEMORY_OVERHEAD_BYTES, MAP_OVERHEAD_ESTIMATE_PERCENT, DEFAULT_INDEX_MEMORY_WARNING_THRESHOLD, INDEX_MEMORY_EVICTION_TARGET, DEFAULT_AVG_KEY_LENGTH_CHARS, } from '../config/memory';
97
+ import { assertNever } from '../types/utilities';
98
+ // =============================================================================
99
+ // Local Constant Aliases (for internal use)
100
+ // =============================================================================
101
+ /** Estimated bytes per index entry */
102
+ const ENTRY_MEMORY_OVERHEAD_BYTES = INDEX_ENTRY_MEMORY_OVERHEAD_BYTES;
103
+ // =============================================================================
104
+ // Timing Constants (local)
105
+ // =============================================================================
106
+ /**
107
+ * Nanoseconds per millisecond for performance timing conversions.
108
+ */
109
+ const NS_PER_MS = 1e6;
110
+ /**
111
+ * TieredStorageOrchestrator - Unified Tiering System
112
+ *
113
+ * ## Performance Characteristics
114
+ *
115
+ * ### Index Operations
116
+ * - **Lookup (get)**: O(1) average via Map, ~50-100ns typical
117
+ * - **Update (set/modify)**: O(1) average for existing keys, O(1) amortized for new keys
118
+ * - **Eviction**: O(n*k) where n=index size, k=batch size; optimized for k << n
119
+ *
120
+ * ### Memory Usage
121
+ * - **Per-entry overhead**: ~120 bytes base + 2 bytes per character in key
122
+ * - **Example**: 10,000 entries with 20-char keys = ~1.6MB
123
+ * - **Warning threshold**: Configurable, default 80% of maxIndexMemoryBytes
124
+ *
125
+ * ### Eviction Policies
126
+ * - **LRU (default)**: Evicts least recently accessed entries
127
+ * - **LFU**: Evicts least frequently accessed entries
128
+ * - **FIFO**: Evicts oldest entries by creation time
129
+ *
130
+ * ### Hot Path Optimizations
131
+ * - Index entry caching for repeated lookups within promotion checks
132
+ * - Batch eviction to amortize overhead across multiple entries
133
+ * - Partial selection algorithm for eviction (avoids full sort when k << n)
134
+ *
135
+ * @class TieredStorageOrchestrator
136
+ */
137
+ export class TieredStorageOrchestrator {
138
+ cacheLayer;
139
+ swrCacheLayer;
140
+ doStorage;
141
+ r2Layer;
142
+ config;
143
+ storageIndex = new Map();
144
+ indexMemoryBytes = 0;
145
+ maintenanceTimer;
146
+ memoryWarningEmitted = false;
147
+ /**
148
+ * Estimated memory per index entry (key string avg ~20 chars + StorageIndexEntry object)
149
+ *
150
+ * Breakdown:
151
+ * - Map entry overhead: ~40 bytes (key reference + value reference + internal structure)
152
+ * - StorageIndexEntry object: ~80 bytes (8 bytes per field * 9 fields + object overhead)
153
+ * - Total base: ~120 bytes per entry
154
+ * - Key string: 2 bytes per character (JS strings are UTF-16)
155
+ */
156
+ static ENTRY_MEMORY_OVERHEAD = ENTRY_MEMORY_OVERHEAD_BYTES;
157
+ // Performance metrics tracking
158
+ performanceMetrics = {
159
+ lookupCount: 0,
160
+ updateCount: 0,
161
+ evictionCount: 0,
162
+ totalLookupTimeNs: 0,
163
+ totalUpdateTimeNs: 0,
164
+ totalEvictionTimeNs: 0,
165
+ totalMaintenanceTimeNs: 0,
166
+ peakEntries: 0,
167
+ peakMemoryBytes: 0,
168
+ evictionBatches: 0,
169
+ cacheHitCount: 0,
170
+ cacheMissCount: 0,
171
+ };
172
+ // Cache for hot path optimization - stores recently looked up entry for promotion check
173
+ lastLookupKey = null;
174
+ lastLookupEntry = null;
175
+ warmStats = { reads: 0, writes: 0, deletes: 0, bytesRead: 0, bytesWritten: 0 };
176
+ promotionStats = { coldToWarm: 0, warmToHot: 0, failed: 0 };
177
+ demotionStats = { hotToWarm: 0, warmToCold: 0, failed: 0 };
178
+ tierHealth = { hot: 'healthy', warm: 'healthy', cold: 'healthy' };
179
+ circuitBreakers = {
180
+ hot: { state: 'closed', failures: 0 },
181
+ warm: { state: 'closed', failures: 0 },
182
+ cold: { state: 'closed', failures: 0 },
183
+ };
184
+ latencyMeasurements = [];
185
+ demotionStrategies = {};
186
+ autoPromoterConfig = { coldToWarm: { accessThreshold: DEFAULT_COLD_TO_WARM_THRESHOLD }, warmToHot: { accessThreshold: DEFAULT_WARM_TO_HOT_THRESHOLD } };
187
+ autoDemoterConfig = { hotToWarm: { ttlMs: DEFAULT_HOT_TTL_MS }, warmToCold: { ttlMs: DEFAULT_WARM_TTL_MS } };
188
+ migrationCallbacks = [];
189
+ errorObservers = [];
190
+ circuitBreakerObservers = [];
191
+ errorCounts = { hot: 0, warm: 0, cold: 0 };
192
+ keyRetryCounters = new Map();
193
+ correlationCounter = 0;
194
+ eventSubscribers = [];
195
+ entryPriorities = new Map();
196
+ pinnedEntries = new Set();
197
+ memoryLimits = {};
198
+ constructor(config) {
199
+ this.cacheLayer = config.cacheLayer;
200
+ this.swrCacheLayer = config.swrCacheLayer;
201
+ this.doStorage = config.doStorage;
202
+ this.r2Layer = config.r2Layer;
203
+ this.config = {
204
+ pageSize: config.pageSize ?? DEFAULT_PAGE_SIZE,
205
+ coldToWarmThreshold: config.coldToWarmThreshold ?? DEFAULT_COLD_TO_WARM_THRESHOLD,
206
+ warmToHotThreshold: config.warmToHotThreshold ?? DEFAULT_WARM_TO_HOT_THRESHOLD,
207
+ promotionWindowMs: config.promotionWindowMs ?? DEFAULT_PROMOTION_WINDOW_MS,
208
+ hotTtlMs: config.hotTtlMs ?? DEFAULT_HOT_TTL_MS,
209
+ warmTtlMs: config.warmTtlMs ?? DEFAULT_WARM_TTL_MS,
210
+ maxHotPages: config.maxHotPages ?? DEFAULT_MAX_HOT_PAGES,
211
+ autoPromote: config.autoPromote ?? true,
212
+ autoDemote: config.autoDemote ?? true,
213
+ writeThrough: config.writeThrough ?? false,
214
+ doPrefix: config.doPrefix ?? DEFAULT_DO_PREFIX,
215
+ circuitBreaker: config.circuitBreaker,
216
+ metrics: config.metrics,
217
+ logger: config.logger,
218
+ // Index bounds configuration
219
+ maxIndexEntries: config.maxIndexEntries,
220
+ maxIndexMemoryBytes: config.maxIndexMemoryBytes,
221
+ indexEvictionPolicy: config.indexEvictionPolicy ?? 'lru',
222
+ indexEvictionBatchSize: config.indexEvictionBatchSize ?? DEFAULT_INDEX_EVICTION_BATCH_SIZE,
223
+ indexMemoryWarningThreshold: config.indexMemoryWarningThreshold ?? DEFAULT_INDEX_MEMORY_WARNING_THRESHOLD,
224
+ indexMaintenanceIntervalMs: config.indexMaintenanceIntervalMs,
225
+ onIndexEviction: config.onIndexEviction,
226
+ };
227
+ this.autoPromoterConfig = {
228
+ coldToWarm: { accessThreshold: this.config.coldToWarmThreshold },
229
+ warmToHot: { accessThreshold: this.config.warmToHotThreshold, timeWindowMs: this.config.promotionWindowMs },
230
+ };
231
+ this.autoDemoterConfig = {
232
+ hotToWarm: { ttlMs: this.config.hotTtlMs },
233
+ warmToCold: { ttlMs: this.config.warmTtlMs },
234
+ };
235
+ // Start maintenance timer if configured
236
+ if (this.config.indexMaintenanceIntervalMs) {
237
+ this.startIndexMaintenance();
238
+ }
239
+ }
240
+ onMigration(callback) { this.migrationCallbacks.push(callback); }
241
+ onError(callback) { this.errorObservers.push(callback); }
242
+ onCircuitBreakerChange(callback) { this.circuitBreakerObservers.push(callback); }
243
+ notifyError(error) {
244
+ if (error.tier)
245
+ this.errorCounts[error.tier]++;
246
+ if (this.config.logger) {
247
+ if (error.context === 'tier_read_failure' && error.tier) {
248
+ this.config.logger.warn(`${error.tier} tier read failed: ${error.error.message}${error.key ? ` (key: ${error.key})` : ''}`);
249
+ }
250
+ else {
251
+ this.config.logger.warn(`${error.context}: ${error.error.message}${error.key ? ` (key: ${error.key})` : ''}${error.tier ? ` (tier: ${error.tier})` : ''}`);
252
+ }
253
+ }
254
+ for (const callback of this.errorObservers) {
255
+ try {
256
+ callback(error);
257
+ }
258
+ catch { /* ignore observer errors */ }
259
+ }
260
+ }
261
+ notifyCircuitBreakerChange(event) {
262
+ this.config.logger?.warn(`Circuit breaker ${event.tier} changed to ${event.state} (failures: ${event.failures})`);
263
+ for (const callback of this.circuitBreakerObservers) {
264
+ try {
265
+ callback(event);
266
+ }
267
+ catch { /* ignore observer errors */ }
268
+ }
269
+ }
270
+ notifyMigration(event) {
271
+ for (const callback of this.migrationCallbacks) {
272
+ try {
273
+ callback(event);
274
+ }
275
+ catch (e) {
276
+ const error = e instanceof Error ? e : new Error(String(e));
277
+ this.notifyError({
278
+ context: 'migration_callback',
279
+ error,
280
+ key: event.key,
281
+ timestamp: Date.now(),
282
+ });
283
+ }
284
+ }
285
+ // Also notify event subscribers
286
+ if (this.eventSubscribers && this.eventSubscribers.length > 0) {
287
+ const isPromotion = event.toTier === 'hot' || (event.fromTier === 'cold' && event.toTier === 'warm');
288
+ for (const { callback, filter } of this.eventSubscribers) {
289
+ if (filter?.type === 'promotion' && !isPromotion)
290
+ continue;
291
+ if (filter?.type === 'demotion' && isPromotion)
292
+ continue;
293
+ try {
294
+ callback(event);
295
+ }
296
+ catch { /* ignore */ }
297
+ }
298
+ }
299
+ }
300
+ doKey(key) { return `${this.config.doPrefix}${key}`; }
301
+ /**
302
+ * High-resolution timer for performance measurement
303
+ * Uses performance.now() when available, falls back to Date.now() * 1e6
304
+ */
305
+ getNowNs() {
306
+ if (typeof performance !== 'undefined' && performance.now) {
307
+ return performance.now() * NS_PER_MS; // Convert ms to ns
308
+ }
309
+ return Date.now() * NS_PER_MS;
310
+ }
311
+ /**
312
+ * Update the storage index with entry information
313
+ *
314
+ * Performance characteristics:
315
+ * - O(1) for existing keys (direct Map update)
316
+ * - O(1) amortized for new keys (may trigger eviction)
317
+ * - Tracks timing for performance metrics
318
+ *
319
+ * @param key - The storage key
320
+ * @param tier - The storage tier where data resides
321
+ * @param size - Size of the data in bytes
322
+ * @param dirty - Whether the entry has uncommitted changes
323
+ */
324
+ updateIndex(key, tier, size, dirty = false) {
325
+ const startNs = this.getNowNs();
326
+ this.performanceMetrics.updateCount++;
327
+ const existing = this.storageIndex.get(key);
328
+ const now = Date.now();
329
+ if (existing) {
330
+ existing.tier = tier;
331
+ existing.size = size;
332
+ existing.lastAccess = now;
333
+ existing.accessCount++;
334
+ existing.modified = now;
335
+ existing.dirty = dirty;
336
+ // Invalidate lookup cache if this was the cached entry
337
+ if (this.lastLookupKey === key) {
338
+ this.lastLookupEntry = existing;
339
+ }
340
+ }
341
+ else {
342
+ // Check if we need to evict before adding
343
+ this.enforceIndexBounds();
344
+ const newEntry = { key, tier, size, lastAccess: now, accessCount: 1, created: now, modified: now, dirty };
345
+ this.storageIndex.set(key, newEntry);
346
+ // Update memory tracking
347
+ this.indexMemoryBytes += TieredStorageOrchestrator.ENTRY_MEMORY_OVERHEAD + key.length * 2;
348
+ // Track peak values
349
+ if (this.storageIndex.size > this.performanceMetrics.peakEntries) {
350
+ this.performanceMetrics.peakEntries = this.storageIndex.size;
351
+ }
352
+ if (this.indexMemoryBytes > this.performanceMetrics.peakMemoryBytes) {
353
+ this.performanceMetrics.peakMemoryBytes = this.indexMemoryBytes;
354
+ }
355
+ // Check memory warning threshold
356
+ this.checkMemoryWarning();
357
+ }
358
+ this.performanceMetrics.totalUpdateTimeNs += this.getNowNs() - startNs;
359
+ }
360
+ /**
361
+ * Enforce index bounds by evicting entries if necessary
362
+ */
363
+ enforceIndexBounds() {
364
+ // Check entry count limit
365
+ if (this.config.maxIndexEntries && this.storageIndex.size >= this.config.maxIndexEntries) {
366
+ this.evictIndexEntries(this.config.indexEvictionBatchSize);
367
+ }
368
+ // Check memory limit
369
+ if (this.config.maxIndexMemoryBytes && this.indexMemoryBytes >= this.config.maxIndexMemoryBytes) {
370
+ // Estimate how many entries to evict based on average entry size
371
+ const avgEntrySize = this.indexMemoryBytes / Math.max(1, this.storageIndex.size);
372
+ const targetBytes = this.config.maxIndexMemoryBytes * INDEX_MEMORY_EVICTION_TARGET; // Target 80% of limit
373
+ const bytesToFree = this.indexMemoryBytes - targetBytes;
374
+ const entriesToEvict = Math.max(1, Math.ceil(bytesToFree / avgEntrySize));
375
+ this.evictIndexEntries(entriesToEvict);
376
+ }
377
+ }
378
+ /**
379
+ * Select the k entries with the smallest scores (partial selection)
380
+ *
381
+ * Uses a simple O(n*k) algorithm which is efficient when k << n.
382
+ * For large k values, this degrades gracefully but still avoids
383
+ * the memory overhead of creating and sorting a full array copy.
384
+ */
385
+ selectSmallestEntries(k, getScore) {
386
+ const result = [];
387
+ const resultScores = [];
388
+ for (const entry of this.storageIndex.values()) {
389
+ const score = getScore(entry);
390
+ if (result.length < k) {
391
+ // Still building up the result set
392
+ result.push(entry);
393
+ resultScores.push(score);
394
+ }
395
+ else {
396
+ // Find the entry with the highest score in our result (the one to potentially replace)
397
+ let maxIdx = 0;
398
+ let maxScore = resultScores[0] ?? 0;
399
+ for (let i = 1; i < resultScores.length; i++) {
400
+ const currentScore = resultScores[i] ?? 0;
401
+ if (currentScore > maxScore) {
402
+ maxIdx = i;
403
+ maxScore = currentScore;
404
+ }
405
+ }
406
+ // If this entry has a lower score, replace the max
407
+ if (score < maxScore) {
408
+ result[maxIdx] = entry;
409
+ resultScores[maxIdx] = score;
410
+ }
411
+ }
412
+ }
413
+ return result;
414
+ }
415
+ /**
416
+ * Evict entries from the index based on configured policy
417
+ *
418
+ * ## Performance Characteristics
419
+ *
420
+ * **Time Complexity**: O(n*k) where n=index size, k=entries to evict
421
+ * - Uses partial selection instead of full sort O(n log n)
422
+ * - Efficient when k << n (typical case: k=10-20, n=10000+)
423
+ *
424
+ * **Space Complexity**: O(k) for the result buffer
425
+ * - Does not create intermediate arrays of size n
426
+ *
427
+ * **Memory optimization**: Uses partial selection instead of full sort.
428
+ * This is more efficient when evicting a small batch from a large index.
429
+ *
430
+ * @param count - Number of entries to evict
431
+ */
432
+ evictIndexEntries(count) {
433
+ if (this.storageIndex.size === 0 || count <= 0)
434
+ return;
435
+ const startNs = this.getNowNs();
436
+ // Select comparison function based on policy
437
+ let getScore;
438
+ switch (this.config.indexEvictionPolicy) {
439
+ case 'lfu':
440
+ // Least Frequently Used - lower accessCount = evict first
441
+ getScore = (e) => e.accessCount;
442
+ break;
443
+ case 'fifo':
444
+ // First In First Out - older created = evict first
445
+ getScore = (e) => e.created;
446
+ break;
447
+ case 'lru':
448
+ default:
449
+ // Least Recently Used - older lastAccess = evict first
450
+ getScore = (e) => e.lastAccess;
451
+ break;
452
+ }
453
+ // Use partial selection: find the k entries with smallest scores
454
+ // This avoids full sort when count << size
455
+ const toEvict = this.selectSmallestEntries(count, getScore);
456
+ const evictedKeys = [];
457
+ for (const entry of toEvict) {
458
+ this.storageIndex.delete(entry.key);
459
+ this.indexMemoryBytes -= TieredStorageOrchestrator.ENTRY_MEMORY_OVERHEAD + entry.key.length * 2;
460
+ evictedKeys.push(entry.key);
461
+ // Invalidate lookup cache if evicted
462
+ if (this.lastLookupKey === entry.key) {
463
+ this.lastLookupKey = null;
464
+ this.lastLookupEntry = null;
465
+ }
466
+ }
467
+ // Update performance metrics
468
+ this.performanceMetrics.evictionCount += evictedKeys.length;
469
+ this.performanceMetrics.evictionBatches++;
470
+ this.performanceMetrics.totalEvictionTimeNs += this.getNowNs() - startNs;
471
+ // Ensure memory tracking doesn't go negative
472
+ if (this.indexMemoryBytes < 0)
473
+ this.indexMemoryBytes = 0;
474
+ // Notify callback if configured
475
+ if (this.config.onIndexEviction && evictedKeys.length > 0) {
476
+ try {
477
+ this.config.onIndexEviction(evictedKeys);
478
+ }
479
+ catch (e) {
480
+ // Ignore callback errors
481
+ this.config.logger?.warn(`Index eviction callback error: ${e instanceof Error ? e.message : String(e)}`);
482
+ }
483
+ }
484
+ }
485
+ /**
486
+ * Check and emit memory warning if threshold exceeded
487
+ */
488
+ checkMemoryWarning() {
489
+ if (!this.config.maxIndexMemoryBytes || this.memoryWarningEmitted)
490
+ return;
491
+ const threshold = this.config.maxIndexMemoryBytes * this.config.indexMemoryWarningThreshold;
492
+ if (this.indexMemoryBytes >= threshold) {
493
+ this.memoryWarningEmitted = true;
494
+ this.config.logger?.warn(`Index memory approaching limit: ${this.indexMemoryBytes} bytes (${Math.round(this.indexMemoryBytes / this.config.maxIndexMemoryBytes * 100)}% of ${this.config.maxIndexMemoryBytes} bytes)`);
495
+ }
496
+ }
497
+ /**
498
+ * Start periodic index maintenance
499
+ */
500
+ startIndexMaintenance() {
501
+ if (this.maintenanceTimer)
502
+ return;
503
+ this.maintenanceTimer = setInterval(async () => {
504
+ try {
505
+ await this.runIndexMaintenance();
506
+ }
507
+ catch (e) {
508
+ this.config.logger?.warn(`Index maintenance error: ${e instanceof Error ? e.message : String(e)}`);
509
+ }
510
+ }, this.config.indexMaintenanceIntervalMs);
511
+ }
512
+ /**
513
+ * Stop periodic index maintenance
514
+ */
515
+ stopIndexMaintenance() {
516
+ if (this.maintenanceTimer) {
517
+ clearInterval(this.maintenanceTimer);
518
+ this.maintenanceTimer = undefined;
519
+ }
520
+ }
521
+ /**
522
+ * Run index maintenance - clean up stale entries
523
+ *
524
+ * ## Performance Characteristics
525
+ *
526
+ * **Time Complexity**: O(n * storage_ops) where n = index entries
527
+ * - Each entry may require 1-2 storage lookups
528
+ * - Storage ops are async and may have network latency
529
+ *
530
+ * **When to Run**:
531
+ * - Periodically via indexMaintenanceIntervalMs config
532
+ * - After suspected data loss or corruption
533
+ * - During low-traffic periods to avoid impacting hot path
534
+ *
535
+ * @returns Object with count of removed stale entries and timing info
536
+ */
537
+ async runIndexMaintenance() {
538
+ const startNs = this.getNowNs();
539
+ let removed = 0;
540
+ const keysToRemove = [];
541
+ for (const [key, entry] of this.storageIndex) {
542
+ // Check if data still exists in the indicated tier
543
+ let exists = false;
544
+ if (entry.tier === 'hot') {
545
+ // Hot tier - assume it might have been evicted, check warm/cold
546
+ const warmData = await this.doStorage.get(this.doKey(key));
547
+ if (warmData) {
548
+ entry.tier = 'warm';
549
+ exists = true;
550
+ }
551
+ else {
552
+ const coldData = await this.r2Layer.get(key);
553
+ if (coldData) {
554
+ entry.tier = 'cold';
555
+ exists = true;
556
+ }
557
+ }
558
+ }
559
+ else if (entry.tier === 'warm') {
560
+ const warmData = await this.doStorage.get(this.doKey(key));
561
+ if (warmData) {
562
+ exists = true;
563
+ }
564
+ else {
565
+ const coldData = await this.r2Layer.get(key);
566
+ if (coldData) {
567
+ entry.tier = 'cold';
568
+ exists = true;
569
+ }
570
+ }
571
+ }
572
+ else {
573
+ const coldData = await this.r2Layer.get(key);
574
+ exists = !!coldData;
575
+ }
576
+ if (!exists) {
577
+ keysToRemove.push(key);
578
+ }
579
+ }
580
+ for (const key of keysToRemove) {
581
+ const entry = this.storageIndex.get(key);
582
+ if (entry) {
583
+ this.storageIndex.delete(key);
584
+ this.indexMemoryBytes -= TieredStorageOrchestrator.ENTRY_MEMORY_OVERHEAD + key.length * 2;
585
+ removed++;
586
+ // Invalidate cache if needed
587
+ if (this.lastLookupKey === key) {
588
+ this.lastLookupKey = null;
589
+ this.lastLookupEntry = null;
590
+ }
591
+ }
592
+ }
593
+ if (this.indexMemoryBytes < 0)
594
+ this.indexMemoryBytes = 0;
595
+ const durationNs = this.getNowNs() - startNs;
596
+ this.performanceMetrics.totalMaintenanceTimeNs += durationNs;
597
+ return { removed, durationMs: durationNs / 1e6 };
598
+ }
599
+ /**
600
+ * Optimized index lookup with single-entry cache
601
+ *
602
+ * The hot path often involves looking up the same key multiple times
603
+ * in quick succession (read -> check promotion -> update index).
604
+ * This cache avoids redundant Map lookups.
605
+ *
606
+ * @param key - The key to look up
607
+ * @returns The index entry or undefined if not found
608
+ */
609
+ getIndexEntryOptimized(key) {
610
+ const startNs = this.getNowNs();
611
+ this.performanceMetrics.lookupCount++;
612
+ // Check single-entry cache first (hot path optimization)
613
+ if (this.lastLookupKey === key && this.lastLookupEntry) {
614
+ this.performanceMetrics.cacheHitCount++;
615
+ this.performanceMetrics.totalLookupTimeNs += this.getNowNs() - startNs;
616
+ return this.lastLookupEntry;
617
+ }
618
+ this.performanceMetrics.cacheMissCount++;
619
+ const entry = this.storageIndex.get(key);
620
+ // Update cache
621
+ this.lastLookupKey = key;
622
+ this.lastLookupEntry = entry ?? null;
623
+ this.performanceMetrics.totalLookupTimeNs += this.getNowNs() - startNs;
624
+ return entry;
625
+ }
626
+ /**
627
+ * Check if a key should be promoted to a higher tier
628
+ *
629
+ * Uses optimized lookup to avoid redundant Map accesses.
630
+ *
631
+ * @param key - The storage key
632
+ * @param currentTier - The current tier of the data
633
+ * @returns Promotion decision with target tier if applicable
634
+ */
635
+ shouldPromote(key, currentTier) {
636
+ if (!this.config.autoPromote)
637
+ return { promote: false };
638
+ const entry = this.getIndexEntryOptimized(key);
639
+ if (!entry)
640
+ return { promote: false };
641
+ if (currentTier === 'cold' && entry.accessCount >= this.config.coldToWarmThreshold)
642
+ return { promote: true, targetTier: 'warm' };
643
+ if (currentTier === 'warm' && entry.accessCount >= this.config.warmToHotThreshold) {
644
+ const age = Date.now() - entry.created;
645
+ if (age <= this.config.promotionWindowMs)
646
+ return { promote: true, targetTier: 'hot' };
647
+ }
648
+ return { promote: false };
649
+ }
650
+ isCircuitOpen(tier) {
651
+ if (!this.config.circuitBreaker?.enabled)
652
+ return false;
653
+ const cb = this.circuitBreakers[tier];
654
+ if (cb.state === 'open' && cb.openedAt) {
655
+ const resetTimeout = this.config.circuitBreaker.resetTimeoutMs ?? DEFAULT_CIRCUIT_BREAKER_RESET_TIMEOUT_MS;
656
+ if (Date.now() - cb.openedAt >= resetTimeout) {
657
+ cb.state = 'half-open';
658
+ return false;
659
+ }
660
+ }
661
+ return cb.state === 'open';
662
+ }
663
+ recordCircuitBreakerFailure(tier, error) {
664
+ if (!this.config.circuitBreaker?.enabled)
665
+ return;
666
+ const cb = this.circuitBreakers[tier];
667
+ cb.failures++;
668
+ cb.lastFailure = Date.now();
669
+ if (cb.failures >= (this.config.circuitBreaker.failureThreshold ?? DEFAULT_CIRCUIT_BREAKER_FAILURE_THRESHOLD)) {
670
+ cb.state = 'open';
671
+ cb.openedAt = Date.now();
672
+ this.notifyCircuitBreakerChange({ tier, state: 'open', failures: cb.failures, error });
673
+ }
674
+ }
675
+ recordCircuitBreakerSuccess(tier) {
676
+ if (!this.config.circuitBreaker?.enabled)
677
+ return;
678
+ const cb = this.circuitBreakers[tier];
679
+ cb.lastSuccess = Date.now();
680
+ if (cb.state === 'half-open') {
681
+ cb.state = 'closed';
682
+ cb.failures = 0;
683
+ }
684
+ }
685
+ async read(key, options) {
686
+ const startTime = this.config.metrics?.trackLatency ? Date.now() : 0;
687
+ const skipPromotion = options?.skipPromotion ?? false;
688
+ const skipTracking = options?.skipTracking ?? false;
689
+ const ctx = options?.ctx;
690
+ const correlationId = `read-${++this.correlationCounter}`;
691
+ const retryCount = this.keyRetryCounters.get(key) ?? 0;
692
+ this.keyRetryCounters.set(key, retryCount + 1);
693
+ const coldCircuitOpen = this.isCircuitOpen('cold');
694
+ const recordLatency = () => { if (this.config.metrics?.trackLatency && startTime > 0) {
695
+ this.latencyMeasurements.push(Date.now() - startTime);
696
+ if (this.latencyMeasurements.length > 1000)
697
+ this.latencyMeasurements.shift();
698
+ } };
699
+ if (this.swrCacheLayer) {
700
+ try {
701
+ const result = await this.swrCacheLayer.get(key, ctx);
702
+ if (result.hit) {
703
+ if (!skipTracking)
704
+ this.updateIndex(key, 'hot', result.data?.length ?? 0);
705
+ this.recordCircuitBreakerSuccess('hot');
706
+ recordLatency();
707
+ return { data: result.data, tier: 'hot', stale: result.stale, revalidating: result.revalidating };
708
+ }
709
+ }
710
+ catch (e) {
711
+ const error = e instanceof Error ? e : new Error(String(e));
712
+ this.tierHealth.hot = 'degraded';
713
+ this.recordCircuitBreakerFailure('hot', error);
714
+ this.notifyError({ context: 'tier_read_failure', error, tier: 'hot', key, timestamp: Date.now(), retryCount, correlationId });
715
+ }
716
+ }
717
+ else if (this.cacheLayer) {
718
+ try {
719
+ const cached = await this.cacheLayer.get(key);
720
+ if (cached) {
721
+ if (!skipTracking)
722
+ this.updateIndex(key, 'hot', cached.length);
723
+ this.recordCircuitBreakerSuccess('hot');
724
+ recordLatency();
725
+ return { data: cached, tier: 'hot' };
726
+ }
727
+ }
728
+ catch (e) {
729
+ const error = e instanceof Error ? e : new Error(String(e));
730
+ this.tierHealth.hot = 'degraded';
731
+ this.recordCircuitBreakerFailure('hot', error);
732
+ this.notifyError({ context: 'tier_read_failure', error, tier: 'hot', key, timestamp: Date.now(), retryCount, correlationId });
733
+ }
734
+ }
735
+ try {
736
+ const doData = await this.doStorage.get(this.doKey(key));
737
+ if (doData) {
738
+ this.warmStats.reads++;
739
+ this.warmStats.bytesRead += doData.length;
740
+ if (!skipTracking)
741
+ this.updateIndex(key, 'warm', doData.length);
742
+ this.recordCircuitBreakerSuccess('warm');
743
+ if (!skipPromotion) {
744
+ const { promote, targetTier } = this.shouldPromote(key, 'warm');
745
+ if (promote && targetTier === 'hot')
746
+ this.promoteToHot(key, doData).catch(() => { });
747
+ }
748
+ recordLatency();
749
+ return { data: doData, tier: 'warm', fallback: coldCircuitOpen ? true : undefined };
750
+ }
751
+ }
752
+ catch (e) {
753
+ const error = e instanceof Error ? e : new Error(String(e));
754
+ this.tierHealth.warm = 'degraded';
755
+ this.recordCircuitBreakerFailure('warm', error);
756
+ this.notifyError({ context: 'tier_read_failure', error, tier: 'warm', key, timestamp: Date.now(), retryCount, correlationId });
757
+ }
758
+ if (coldCircuitOpen) {
759
+ recordLatency();
760
+ return { data: null };
761
+ }
762
+ try {
763
+ const r2Data = await this.r2Layer.get(key);
764
+ if (r2Data) {
765
+ if (!skipTracking)
766
+ this.updateIndex(key, 'cold', r2Data.length);
767
+ this.recordCircuitBreakerSuccess('cold');
768
+ if (!skipPromotion) {
769
+ const { promote, targetTier } = this.shouldPromote(key, 'cold');
770
+ if (promote && targetTier === 'warm')
771
+ this.promoteToWarm(key, r2Data).catch(() => { });
772
+ }
773
+ recordLatency();
774
+ return { data: r2Data, tier: 'cold' };
775
+ }
776
+ }
777
+ catch (e) {
778
+ const error = e instanceof Error ? e : new Error(String(e));
779
+ this.tierHealth.cold = 'degraded';
780
+ this.recordCircuitBreakerFailure('cold', error);
781
+ this.notifyError({ context: 'tier_read_failure', error, tier: 'cold', key, timestamp: Date.now(), retryCount, correlationId });
782
+ }
783
+ recordLatency();
784
+ return { data: null };
785
+ }
786
+ async write(key, data, options) {
787
+ const tier = options?.tier ?? 'warm';
788
+ const writeThrough = options?.writeThrough ?? this.config.writeThrough;
789
+ const skipIndex = options?.skipIndex ?? false;
790
+ switch (tier) {
791
+ case 'hot':
792
+ await this.doStorage.put(this.doKey(key), data);
793
+ this.warmStats.writes++;
794
+ this.warmStats.bytesWritten += data.length;
795
+ if (this.swrCacheLayer)
796
+ await this.swrCacheLayer.put(key, data);
797
+ else if (this.cacheLayer)
798
+ await this.cacheLayer.put(key, data, { lastAccessed: Date.now(), accessCount: 1 });
799
+ if (!skipIndex)
800
+ this.updateIndex(key, 'hot', data.length, writeThrough ? false : true);
801
+ break;
802
+ case 'warm':
803
+ await this.doStorage.put(this.doKey(key), data);
804
+ this.warmStats.writes++;
805
+ this.warmStats.bytesWritten += data.length;
806
+ if (!skipIndex)
807
+ this.updateIndex(key, 'warm', data.length, writeThrough ? false : true);
808
+ break;
809
+ case 'cold':
810
+ await this.r2Layer.put(key, data, { customMetadata: options?.metadata });
811
+ if (!skipIndex)
812
+ this.updateIndex(key, 'cold', data.length, false);
813
+ break;
814
+ }
815
+ if (writeThrough && tier !== 'cold') {
816
+ try {
817
+ await this.r2Layer.put(key, data, { customMetadata: { ...options?.metadata, writeThroughAt: Date.now().toString(), sourceTier: tier } });
818
+ const entry = this.storageIndex.get(key);
819
+ if (entry)
820
+ entry.dirty = false;
821
+ }
822
+ catch (e) {
823
+ const error = e instanceof Error ? e : new Error(String(e));
824
+ this.tierHealth.cold = 'degraded';
825
+ this.notifyError({ context: 'write_through_failure', error, tier: 'cold', key, timestamp: Date.now() });
826
+ }
827
+ }
828
+ }
829
+ async delete(key) {
830
+ const errors = [];
831
+ if (this.swrCacheLayer) {
832
+ try {
833
+ await this.swrCacheLayer.invalidate(key);
834
+ }
835
+ catch (e) {
836
+ errors.push(e instanceof Error ? e : new Error(String(e)));
837
+ }
838
+ }
839
+ else if (this.cacheLayer) {
840
+ try {
841
+ await this.cacheLayer.delete(key);
842
+ }
843
+ catch (e) {
844
+ errors.push(e instanceof Error ? e : new Error(String(e)));
845
+ }
846
+ }
847
+ try {
848
+ await this.doStorage.delete(this.doKey(key));
849
+ this.warmStats.deletes++;
850
+ }
851
+ catch (e) {
852
+ errors.push(e instanceof Error ? e : new Error(String(e)));
853
+ }
854
+ try {
855
+ await this.r2Layer.delete(key);
856
+ }
857
+ catch (e) {
858
+ errors.push(e instanceof Error ? e : new Error(String(e)));
859
+ }
860
+ // Update memory tracking before deleting from index
861
+ if (this.storageIndex.has(key)) {
862
+ this.indexMemoryBytes -= TieredStorageOrchestrator.ENTRY_MEMORY_OVERHEAD + key.length * 2;
863
+ if (this.indexMemoryBytes < 0)
864
+ this.indexMemoryBytes = 0;
865
+ }
866
+ this.storageIndex.delete(key);
867
+ if (errors.length === 3)
868
+ throw new Error(`Failed to delete from all tiers: ${errors.map(e => e.message).join('; ')}`);
869
+ }
870
+ async promoteToWarm(key, data) {
871
+ const timestamp = Date.now();
872
+ const pageData = data ?? await this.r2Layer.get(key);
873
+ if (!pageData) {
874
+ const event = { key, fromTier: 'cold', toTier: 'warm', success: false, timestamp, error: 'Data not found in cold tier', reason: 'access_pattern' };
875
+ this.promotionStats.failed++;
876
+ this.notifyMigration(event);
877
+ return event;
878
+ }
879
+ try {
880
+ await this.doStorage.put(this.doKey(key), pageData);
881
+ this.warmStats.writes++;
882
+ this.warmStats.bytesWritten += pageData.length;
883
+ this.promotionStats.coldToWarm++;
884
+ this.updateIndex(key, 'warm', pageData.length);
885
+ const event = { key, fromTier: 'cold', toTier: 'warm', success: true, timestamp, reason: 'access_pattern' };
886
+ this.notifyMigration(event);
887
+ return event;
888
+ }
889
+ catch (e) {
890
+ this.promotionStats.failed++;
891
+ const event = { key, fromTier: 'cold', toTier: 'warm', success: false, timestamp, error: e instanceof Error ? e.message : String(e), reason: 'access_pattern' };
892
+ this.notifyMigration(event);
893
+ return event;
894
+ }
895
+ }
896
+ async promoteToHot(key, data) {
897
+ const timestamp = Date.now();
898
+ const pageData = data ?? await this.doStorage.get(this.doKey(key));
899
+ if (!pageData) {
900
+ const event = { key, fromTier: 'warm', toTier: 'hot', success: false, timestamp, error: 'Data not found in warm tier', reason: 'access_pattern' };
901
+ this.promotionStats.failed++;
902
+ this.notifyMigration(event);
903
+ return event;
904
+ }
905
+ try {
906
+ if (this.swrCacheLayer)
907
+ await this.swrCacheLayer.put(key, pageData);
908
+ else if (this.cacheLayer) {
909
+ const entry = this.storageIndex.get(key);
910
+ await this.cacheLayer.put(key, pageData, { lastAccessed: timestamp, accessCount: entry?.accessCount ?? 1 });
911
+ }
912
+ this.promotionStats.warmToHot++;
913
+ this.updateIndex(key, 'hot', pageData.length);
914
+ const event = { key, fromTier: 'warm', toTier: 'hot', success: true, timestamp, reason: 'access_pattern' };
915
+ this.notifyMigration(event);
916
+ return event;
917
+ }
918
+ catch (e) {
919
+ this.promotionStats.failed++;
920
+ const event = { key, fromTier: 'warm', toTier: 'hot', success: false, timestamp, error: e instanceof Error ? e.message : String(e), reason: 'access_pattern' };
921
+ this.notifyMigration(event);
922
+ return event;
923
+ }
924
+ }
925
+ async demoteFromHot(key, reason = 'ttl_expired') {
926
+ const timestamp = Date.now();
927
+ try {
928
+ if (this.swrCacheLayer)
929
+ await this.swrCacheLayer.invalidate(key);
930
+ else if (this.cacheLayer)
931
+ await this.cacheLayer.delete(key);
932
+ this.demotionStats.hotToWarm++;
933
+ this.updateIndex(key, 'warm', this.storageIndex.get(key)?.size ?? 0);
934
+ const event = { key, fromTier: 'hot', toTier: 'warm', success: true, timestamp, reason };
935
+ this.notifyMigration(event);
936
+ return event;
937
+ }
938
+ catch (e) {
939
+ this.demotionStats.failed++;
940
+ const event = { key, fromTier: 'hot', toTier: 'warm', success: false, timestamp, error: e instanceof Error ? e.message : String(e), reason };
941
+ this.notifyMigration(event);
942
+ return event;
943
+ }
944
+ }
945
+ async demoteFromWarm(key, reason = 'ttl_expired') {
946
+ const timestamp = Date.now();
947
+ try {
948
+ const data = await this.doStorage.get(this.doKey(key));
949
+ if (!data) {
950
+ const event = { key, fromTier: 'warm', toTier: 'cold', success: false, timestamp, error: 'Data not found in warm tier', reason };
951
+ this.demotionStats.failed++;
952
+ this.notifyMigration(event);
953
+ return event;
954
+ }
955
+ await this.r2Layer.put(key, data, { customMetadata: { demotedAt: timestamp.toString(), reason } });
956
+ await this.doStorage.delete(this.doKey(key));
957
+ this.warmStats.deletes++;
958
+ this.demotionStats.warmToCold++;
959
+ this.updateIndex(key, 'cold', data.length);
960
+ const event = { key, fromTier: 'warm', toTier: 'cold', success: true, timestamp, reason };
961
+ this.notifyMigration(event);
962
+ return event;
963
+ }
964
+ catch (e) {
965
+ this.demotionStats.failed++;
966
+ const event = { key, fromTier: 'warm', toTier: 'cold', success: false, timestamp, error: e instanceof Error ? e.message : String(e), reason };
967
+ this.notifyMigration(event);
968
+ return event;
969
+ }
970
+ }
971
+ async runDemotionCycle(maxDemotions = 10) {
972
+ if (!this.config.autoDemote)
973
+ return [];
974
+ const events = [];
975
+ const now = Date.now();
976
+ const hotCandidates = [];
977
+ for (const entry of this.storageIndex.values()) {
978
+ // Skip pinned entries
979
+ if (this.pinnedEntries.has(entry.key))
980
+ continue;
981
+ if (entry.tier === 'hot' && now - entry.lastAccess >= this.config.hotTtlMs)
982
+ hotCandidates.push(entry);
983
+ }
984
+ hotCandidates.sort((a, b) => a.lastAccess - b.lastAccess);
985
+ for (const entry of hotCandidates.slice(0, maxDemotions))
986
+ events.push(await this.demoteFromHot(entry.key));
987
+ const warmCandidates = [];
988
+ for (const entry of this.storageIndex.values()) {
989
+ // Skip pinned entries
990
+ if (this.pinnedEntries.has(entry.key))
991
+ continue;
992
+ if (entry.tier === 'warm' && now - entry.lastAccess >= this.config.warmTtlMs)
993
+ warmCandidates.push(entry);
994
+ }
995
+ warmCandidates.sort((a, b) => a.lastAccess - b.lastAccess);
996
+ const remainingSlots = maxDemotions - events.length;
997
+ for (const entry of warmCandidates.slice(0, remainingSlots))
998
+ events.push(await this.demoteFromWarm(entry.key));
999
+ return events;
1000
+ }
1001
+ async evictLRUFromHot(count) {
1002
+ const hotPages = [];
1003
+ for (const entry of this.storageIndex.values()) {
1004
+ if (entry.tier === 'hot')
1005
+ hotPages.push(entry);
1006
+ }
1007
+ hotPages.sort((a, b) => a.lastAccess - b.lastAccess);
1008
+ const events = [];
1009
+ for (const entry of hotPages.slice(0, count))
1010
+ events.push(await this.demoteFromHot(entry.key, 'lru_eviction'));
1011
+ return events;
1012
+ }
1013
+ async syncDirtyToCold() {
1014
+ let synced = 0;
1015
+ for (const entry of this.storageIndex.values()) {
1016
+ if (entry.dirty) {
1017
+ try {
1018
+ const data = await this.doStorage.get(this.doKey(entry.key));
1019
+ if (data) {
1020
+ await this.r2Layer.put(entry.key, data, { customMetadata: { syncedAt: Date.now().toString(), sourceTier: entry.tier } });
1021
+ entry.dirty = false;
1022
+ synced++;
1023
+ }
1024
+ }
1025
+ catch (e) {
1026
+ const error = e instanceof Error ? e : new Error(String(e));
1027
+ this.notifyError({ context: 'sync_dirty_to_cold', error, key: entry.key, timestamp: Date.now() });
1028
+ }
1029
+ }
1030
+ }
1031
+ return synced;
1032
+ }
1033
+ getIndexEntry(key) { return this.storageIndex.get(key); }
1034
+ hasInIndex(key) { return this.storageIndex.has(key); }
1035
+ getTier(key) { return this.storageIndex.get(key)?.tier; }
1036
+ /**
1037
+ * Get detailed memory usage breakdown for the storage index
1038
+ *
1039
+ * ## Memory Components
1040
+ *
1041
+ * - **entryOverhead**: Fixed overhead per entry (~120 bytes)
1042
+ * - **keyStorage**: Memory for key strings (2 bytes per char in JS)
1043
+ * - **mapOverhead**: Estimated Map internal structures (~10% of entry memory)
1044
+ *
1045
+ * @returns Detailed memory breakdown in bytes
1046
+ */
1047
+ getIndexMemoryBreakdown() {
1048
+ let keyStorage = 0;
1049
+ for (const key of this.storageIndex.keys()) {
1050
+ keyStorage += key.length * 2; // JS strings are UTF-16
1051
+ }
1052
+ const entryOverhead = this.storageIndex.size * TieredStorageOrchestrator.ENTRY_MEMORY_OVERHEAD;
1053
+ // Estimate Map internal overhead as ~10% of entry memory
1054
+ const mapOverheadEstimate = Math.ceil(entryOverhead * MAP_OVERHEAD_ESTIMATE_PERCENT);
1055
+ const totalBytes = entryOverhead + keyStorage + mapOverheadEstimate;
1056
+ const bytesPerEntry = this.storageIndex.size > 0
1057
+ ? totalBytes / this.storageIndex.size
1058
+ : 0;
1059
+ return {
1060
+ totalBytes,
1061
+ entryOverhead,
1062
+ keyStorage,
1063
+ mapOverheadEstimate,
1064
+ bytesPerEntry,
1065
+ entries: this.storageIndex.size,
1066
+ peakBytes: this.performanceMetrics.peakMemoryBytes,
1067
+ utilizationPercent: this.config.maxIndexMemoryBytes
1068
+ ? (this.indexMemoryBytes / this.config.maxIndexMemoryBytes) * 100
1069
+ : null,
1070
+ memoryBudgetBytes: this.config.maxIndexMemoryBytes ?? null,
1071
+ };
1072
+ }
1073
+ /**
1074
+ * Estimate memory for a given number of entries with average key length
1075
+ *
1076
+ * Useful for capacity planning:
1077
+ * ```typescript
1078
+ * // How much memory for 10,000 entries with ~30 char keys?
1079
+ * const estimate = orchestrator.estimateIndexMemory(10000, 30)
1080
+ * console.log(`Estimated: ${estimate / 1024 / 1024}MB`)
1081
+ * ```
1082
+ *
1083
+ * @param entryCount - Number of entries to estimate for
1084
+ * @param avgKeyLength - Average key length in characters (default: 20)
1085
+ * @returns Estimated memory usage in bytes
1086
+ */
1087
+ estimateIndexMemory(entryCount, avgKeyLength = DEFAULT_AVG_KEY_LENGTH_CHARS) {
1088
+ const entryOverhead = entryCount * TieredStorageOrchestrator.ENTRY_MEMORY_OVERHEAD;
1089
+ const keyStorage = entryCount * avgKeyLength * 2; // UTF-16
1090
+ const mapOverhead = Math.ceil(entryOverhead * MAP_OVERHEAD_ESTIMATE_PERCENT);
1091
+ return entryOverhead + keyStorage + mapOverhead;
1092
+ }
1093
+ /**
1094
+ * Get the current memory usage as a percentage of the configured limit
1095
+ *
1096
+ * @returns Percentage (0-100) or null if no limit configured
1097
+ */
1098
+ getIndexMemoryUtilization() {
1099
+ if (!this.config.maxIndexMemoryBytes)
1100
+ return null;
1101
+ return (this.indexMemoryBytes / this.config.maxIndexMemoryBytes) * 100;
1102
+ }
1103
+ /**
1104
+ * Check if the index is approaching memory limits
1105
+ *
1106
+ * @param threshold - Warning threshold as decimal (default: 0.8 = 80%)
1107
+ * @returns Object with warning status and details
1108
+ */
1109
+ checkIndexMemoryStatus(threshold = 0.8) {
1110
+ const utilization = this.getIndexMemoryUtilization();
1111
+ return {
1112
+ isNearLimit: utilization !== null && utilization >= threshold * 100,
1113
+ currentBytes: this.indexMemoryBytes,
1114
+ limitBytes: this.config.maxIndexMemoryBytes ?? null,
1115
+ utilizationPercent: utilization,
1116
+ warningThreshold: threshold * 100,
1117
+ };
1118
+ }
1119
+ /**
1120
+ * Get comprehensive statistics including performance metrics
1121
+ *
1122
+ * ## Performance Metrics Included
1123
+ *
1124
+ * - **lookupCount**: Total number of index lookups
1125
+ * - **updateCount**: Total number of index updates
1126
+ * - **evictionCount**: Total entries evicted
1127
+ * - **avgLookupTimeNs**: Average lookup time in nanoseconds
1128
+ * - **avgUpdateTimeNs**: Average update time in nanoseconds
1129
+ * - **peakEntries**: Maximum index size observed
1130
+ * - **peakMemoryBytes**: Maximum memory usage observed
1131
+ * - **cacheHitCount/cacheMissCount**: Hot path cache effectiveness
1132
+ *
1133
+ * @returns Complete orchestrator statistics
1134
+ */
1135
+ getStats() {
1136
+ const indexStats = {
1137
+ totalEntries: this.storageIndex.size,
1138
+ byTier: { hot: 0, warm: 0, cold: 0 },
1139
+ totalSize: 0,
1140
+ dirtyEntries: 0,
1141
+ memoryBytes: this.indexMemoryBytes,
1142
+ performance: {
1143
+ lookupCount: this.performanceMetrics.lookupCount,
1144
+ updateCount: this.performanceMetrics.updateCount,
1145
+ evictionCount: this.performanceMetrics.evictionCount,
1146
+ totalLookupTimeNs: this.performanceMetrics.totalLookupTimeNs,
1147
+ totalUpdateTimeNs: this.performanceMetrics.totalUpdateTimeNs,
1148
+ totalEvictionTimeNs: this.performanceMetrics.totalEvictionTimeNs,
1149
+ totalMaintenanceTimeNs: this.performanceMetrics.totalMaintenanceTimeNs,
1150
+ avgLookupTimeNs: this.performanceMetrics.lookupCount > 0
1151
+ ? this.performanceMetrics.totalLookupTimeNs / this.performanceMetrics.lookupCount
1152
+ : 0,
1153
+ avgUpdateTimeNs: this.performanceMetrics.updateCount > 0
1154
+ ? this.performanceMetrics.totalUpdateTimeNs / this.performanceMetrics.updateCount
1155
+ : 0,
1156
+ peakEntries: this.performanceMetrics.peakEntries,
1157
+ peakMemoryBytes: this.performanceMetrics.peakMemoryBytes,
1158
+ evictionBatches: this.performanceMetrics.evictionBatches,
1159
+ entriesPerEvictionBatch: this.performanceMetrics.evictionBatches > 0
1160
+ ? this.performanceMetrics.evictionCount / this.performanceMetrics.evictionBatches
1161
+ : 0,
1162
+ cacheHitCount: this.performanceMetrics.cacheHitCount,
1163
+ cacheMissCount: this.performanceMetrics.cacheMissCount,
1164
+ },
1165
+ };
1166
+ for (const entry of this.storageIndex.values()) {
1167
+ indexStats.byTier[entry.tier]++;
1168
+ indexStats.totalSize += entry.size;
1169
+ if (entry.dirty)
1170
+ indexStats.dirtyEntries++;
1171
+ }
1172
+ return {
1173
+ index: indexStats,
1174
+ hot: this.swrCacheLayer?.getStats() ?? this.cacheLayer?.getStats() ?? { hits: 0, misses: 0, writes: 0, deletes: 0, bytesRead: 0, bytesWritten: 0, errors: 0, hitRatio: 0 },
1175
+ warm: { ...this.warmStats },
1176
+ cold: this.r2Layer.getStats(),
1177
+ promotions: { ...this.promotionStats },
1178
+ demotions: { ...this.demotionStats },
1179
+ health: { ...this.tierHealth },
1180
+ errors: { ...this.errorCounts },
1181
+ };
1182
+ }
1183
+ /**
1184
+ * Reset all statistics counters
1185
+ *
1186
+ * Resets:
1187
+ * - Warm tier stats (reads, writes, deletes, bytes)
1188
+ * - Promotion/demotion counters
1189
+ * - Performance metrics (lookup/update/eviction counts and timing)
1190
+ *
1191
+ * Does NOT reset:
1192
+ * - Peak values (peakEntries, peakMemoryBytes)
1193
+ * - Current index state
1194
+ */
1195
+ resetStats() {
1196
+ this.warmStats = { reads: 0, writes: 0, deletes: 0, bytesRead: 0, bytesWritten: 0 };
1197
+ this.promotionStats = { coldToWarm: 0, warmToHot: 0, failed: 0 };
1198
+ this.demotionStats = { hotToWarm: 0, warmToCold: 0, failed: 0 };
1199
+ }
1200
+ /**
1201
+ * Reset only performance metrics while preserving operational stats
1202
+ *
1203
+ * Useful for:
1204
+ * - Starting a new measurement window
1205
+ * - Benchmarking specific operations
1206
+ * - A/B testing configuration changes
1207
+ *
1208
+ * @param preservePeaks - If true, keeps peakEntries and peakMemoryBytes (default: false)
1209
+ */
1210
+ resetPerformanceMetrics(preservePeaks = false) {
1211
+ const peakEntries = preservePeaks ? this.performanceMetrics.peakEntries : 0;
1212
+ const peakMemoryBytes = preservePeaks ? this.performanceMetrics.peakMemoryBytes : 0;
1213
+ this.performanceMetrics = {
1214
+ lookupCount: 0,
1215
+ updateCount: 0,
1216
+ evictionCount: 0,
1217
+ totalLookupTimeNs: 0,
1218
+ totalUpdateTimeNs: 0,
1219
+ totalEvictionTimeNs: 0,
1220
+ totalMaintenanceTimeNs: 0,
1221
+ peakEntries,
1222
+ peakMemoryBytes,
1223
+ evictionBatches: 0,
1224
+ cacheHitCount: 0,
1225
+ cacheMissCount: 0,
1226
+ };
1227
+ // Clear lookup cache
1228
+ this.lastLookupKey = null;
1229
+ this.lastLookupEntry = null;
1230
+ }
1231
+ /**
1232
+ * Get a human-readable performance summary
1233
+ *
1234
+ * @returns Formatted string with key performance metrics
1235
+ */
1236
+ getPerformanceSummary() {
1237
+ const m = this.performanceMetrics;
1238
+ const cacheHitRate = (m.cacheHitCount + m.cacheMissCount) > 0
1239
+ ? ((m.cacheHitCount / (m.cacheHitCount + m.cacheMissCount)) * 100).toFixed(1)
1240
+ : '0.0';
1241
+ const avgLookup = m.lookupCount > 0
1242
+ ? (m.totalLookupTimeNs / m.lookupCount / 1000).toFixed(2)
1243
+ : '0.00';
1244
+ const avgUpdate = m.updateCount > 0
1245
+ ? (m.totalUpdateTimeNs / m.updateCount / 1000).toFixed(2)
1246
+ : '0.00';
1247
+ const avgEvictionBatch = m.evictionBatches > 0
1248
+ ? (m.totalEvictionTimeNs / m.evictionBatches / 1000).toFixed(2)
1249
+ : '0.00';
1250
+ return [
1251
+ `Index Performance Summary:`,
1252
+ ` Entries: ${this.storageIndex.size} current, ${m.peakEntries} peak`,
1253
+ ` Memory: ${(this.indexMemoryBytes / 1024).toFixed(1)}KB current, ${(m.peakMemoryBytes / 1024).toFixed(1)}KB peak`,
1254
+ ` Lookups: ${m.lookupCount} total, ${avgLookup}μs avg`,
1255
+ ` Updates: ${m.updateCount} total, ${avgUpdate}μs avg`,
1256
+ ` Evictions: ${m.evictionCount} entries in ${m.evictionBatches} batches, ${avgEvictionBatch}μs/batch`,
1257
+ ` Cache: ${cacheHitRate}% hit rate (${m.cacheHitCount} hits, ${m.cacheMissCount} misses)`,
1258
+ ` Maintenance: ${(m.totalMaintenanceTimeNs / 1e6).toFixed(1)}ms total`,
1259
+ ].join('\n');
1260
+ }
1261
+ /**
1262
+ * Clear the index and all associated tracking
1263
+ */
1264
+ clearIndex() {
1265
+ this.storageIndex.clear();
1266
+ this.indexMemoryBytes = 0;
1267
+ this.memoryWarningEmitted = false;
1268
+ this.lastLookupKey = null;
1269
+ this.lastLookupEntry = null;
1270
+ }
1271
+ resetHealth(tier) {
1272
+ if (tier)
1273
+ this.tierHealth[tier] = 'healthy';
1274
+ else
1275
+ this.tierHealth = { hot: 'healthy', warm: 'healthy', cold: 'healthy' };
1276
+ }
1277
+ getConfig() { return { ...this.config }; }
1278
+ // DO Lifecycle Hooks
1279
+ async onHibernate() {
1280
+ const timestamp = Date.now();
1281
+ let persistedCount = 0;
1282
+ const hotKeys = [];
1283
+ for (const entry of this.storageIndex.values()) {
1284
+ if (entry.tier === 'hot')
1285
+ hotKeys.push(entry.key);
1286
+ }
1287
+ for (const key of hotKeys) {
1288
+ const entry = this.storageIndex.get(key);
1289
+ if (entry) {
1290
+ entry.tier = 'warm';
1291
+ persistedCount++;
1292
+ }
1293
+ }
1294
+ const syncedToCold = await this.syncDirtyToCold();
1295
+ const indexSnapshot = new Map(this.storageIndex);
1296
+ return { success: true, persistedCount, syncedToCold, hotKeys, indexSnapshot, timestamp };
1297
+ }
1298
+ async onWake(hibernateState, options) {
1299
+ let restoredCount = 0, prefetchedCount = 0, indexRepairs = 0;
1300
+ const indexValidated = options?.validateIndex ?? false;
1301
+ if (hibernateState?.hotKeys) {
1302
+ for (const key of hibernateState.hotKeys) {
1303
+ try {
1304
+ const data = await this.doStorage.get(this.doKey(key));
1305
+ if (data) {
1306
+ if (this.swrCacheLayer)
1307
+ await this.swrCacheLayer.put(key, data);
1308
+ else if (this.cacheLayer)
1309
+ await this.cacheLayer.put(key, data, { lastAccessed: Date.now(), accessCount: 1 });
1310
+ this.updateIndex(key, 'hot', data.length);
1311
+ restoredCount++;
1312
+ }
1313
+ }
1314
+ catch (e) {
1315
+ const error = e instanceof Error ? e : new Error(String(e));
1316
+ this.notifyError({ context: 'wake_restore', error, key, timestamp: Date.now() });
1317
+ }
1318
+ }
1319
+ }
1320
+ if (options?.prefetchThreshold && hibernateState?.indexSnapshot) {
1321
+ for (const [key, entry] of hibernateState.indexSnapshot) {
1322
+ if (entry.accessCount >= options.prefetchThreshold && entry.tier !== 'hot') {
1323
+ try {
1324
+ const event = await this.promoteToHot(key);
1325
+ if (event.success)
1326
+ prefetchedCount++;
1327
+ }
1328
+ catch (e) {
1329
+ const error = e instanceof Error ? e : new Error(String(e));
1330
+ this.notifyError({ context: 'wake_prefetch', error, key, timestamp: Date.now() });
1331
+ }
1332
+ }
1333
+ }
1334
+ }
1335
+ if (indexValidated) {
1336
+ for (const [key, entry] of this.storageIndex) {
1337
+ let found = false, actualTier;
1338
+ const warmData = await this.doStorage.get(this.doKey(key));
1339
+ if (warmData) {
1340
+ found = true;
1341
+ actualTier = 'warm';
1342
+ }
1343
+ if (!found) {
1344
+ const coldData = await this.r2Layer.get(key);
1345
+ if (coldData) {
1346
+ found = true;
1347
+ actualTier = 'cold';
1348
+ }
1349
+ }
1350
+ if (!found) {
1351
+ this.storageIndex.delete(key);
1352
+ indexRepairs++;
1353
+ }
1354
+ else if (actualTier && actualTier !== entry.tier && entry.tier !== 'hot') {
1355
+ entry.tier = actualTier;
1356
+ indexRepairs++;
1357
+ }
1358
+ }
1359
+ }
1360
+ return { restoredCount, prefetchedCount, indexValidated, indexRepairs };
1361
+ }
1362
+ // Background Task Scheduling
1363
+ async scheduleAlarm(alarmConfig) {
1364
+ const storage = this.doStorage;
1365
+ if (alarmConfig.skipIfExists && storage.getAlarm) {
1366
+ const existingAlarm = await storage.getAlarm();
1367
+ if (existingAlarm !== null && existingAlarm !== undefined)
1368
+ return;
1369
+ }
1370
+ const scheduledTime = Date.now() + alarmConfig.delayMs;
1371
+ if (storage.setAlarm)
1372
+ await storage.setAlarm(scheduledTime);
1373
+ }
1374
+ async handleAlarm(alarmConfig) {
1375
+ const result = {};
1376
+ switch (alarmConfig.type) {
1377
+ case 'demotion': {
1378
+ const events = await this.runDemotionCycle();
1379
+ result.demotionCount = events.length;
1380
+ break;
1381
+ }
1382
+ case 'sync': {
1383
+ result.syncedCount = await this.syncDirtyToCold();
1384
+ break;
1385
+ }
1386
+ default: assertNever(alarmConfig.type, 'Unknown alarm type');
1387
+ }
1388
+ if (alarmConfig.rescheduleMs) {
1389
+ await this.scheduleAlarm({ type: alarmConfig.type, delayMs: alarmConfig.rescheduleMs });
1390
+ result.nextAlarmMs = alarmConfig.rescheduleMs;
1391
+ }
1392
+ return result;
1393
+ }
1394
+ // Circuit Breaker Pattern
1395
+ getCircuitBreakerState(tier) {
1396
+ const state = { ...this.circuitBreakers[tier] };
1397
+ if (state.state === 'open' && state.openedAt) {
1398
+ const resetTimeout = this.config.circuitBreaker?.resetTimeoutMs ?? DEFAULT_CIRCUIT_BREAKER_RESET_TIMEOUT_MS;
1399
+ if (Date.now() - state.openedAt >= resetTimeout) {
1400
+ this.circuitBreakers[tier].state = 'half-open';
1401
+ state.state = 'half-open';
1402
+ }
1403
+ }
1404
+ return state;
1405
+ }
1406
+ setCircuitBreakerState(tier, state) {
1407
+ this.circuitBreakers[tier].state = state;
1408
+ if (state === 'open')
1409
+ this.circuitBreakers[tier].openedAt = Date.now();
1410
+ }
1411
+ // Metrics Aggregation
1412
+ getAggregatedMetrics() {
1413
+ const hotStats = this.swrCacheLayer?.getStats() ?? this.cacheLayer?.getStats() ?? { hits: 0, misses: 0, writes: 0, bytesRead: 0, bytesWritten: 0, hitRatio: 0 };
1414
+ const coldStats = this.r2Layer.getStats();
1415
+ let warmBytesStored = 0, coldBytesStored = 0;
1416
+ for (const entry of this.storageIndex.values()) {
1417
+ if (entry.tier === 'warm')
1418
+ warmBytesStored += entry.size;
1419
+ if (entry.tier === 'cold')
1420
+ coldBytesStored += entry.size;
1421
+ }
1422
+ const metrics = {
1423
+ timestamp: Date.now(),
1424
+ period: 'current',
1425
+ tiers: {
1426
+ hot: { reads: 'hits' in hotStats ? hotStats.hits + hotStats.misses : 0, writes: hotStats.writes, hitRatio: 'hitRatio' in hotStats ? hotStats.hitRatio : 0, bytesRead: hotStats.bytesRead, bytesWritten: hotStats.bytesWritten },
1427
+ warm: { reads: this.warmStats.reads, writes: this.warmStats.writes, bytesStored: warmBytesStored, bytesRead: this.warmStats.bytesRead, bytesWritten: this.warmStats.bytesWritten },
1428
+ cold: { reads: coldStats.reads, writes: coldStats.writes, bytesStored: coldBytesStored, bytesRead: coldStats.bytesRead, bytesWritten: coldStats.bytesWritten },
1429
+ },
1430
+ migrations: { promotions: this.promotionStats.coldToWarm + this.promotionStats.warmToHot, demotions: this.demotionStats.hotToWarm + this.demotionStats.warmToCold, failures: this.promotionStats.failed + this.demotionStats.failed },
1431
+ circuitBreakers: { hot: this.getCircuitBreakerState('hot'), warm: this.getCircuitBreakerState('warm'), cold: this.getCircuitBreakerState('cold') },
1432
+ errors: { totalErrors: this.errorCounts.hot + this.errorCounts.warm + this.errorCounts.cold, byTier: { ...this.errorCounts } },
1433
+ };
1434
+ if (this.config.metrics?.trackLatency && this.latencyMeasurements.length > 0) {
1435
+ const sorted = [...this.latencyMeasurements].sort((a, b) => a - b);
1436
+ metrics.latency = { p50: sorted[Math.floor(sorted.length * 0.5)] ?? 0, p95: sorted[Math.floor(sorted.length * 0.95)] ?? 0, p99: sorted[Math.floor(sorted.length * 0.99)] ?? 0 };
1437
+ }
1438
+ if (this.config.metrics?.trackCost && this.config.metrics.costConfig) {
1439
+ const cc = this.config.metrics.costConfig;
1440
+ const r2Cost = (coldBytesStored / (1024 * 1024 * 1024)) * cc.r2StoragePerGBMonth + coldStats.writes * cc.r2ClassAOperations + coldStats.reads * cc.r2ClassBOperations;
1441
+ const doCost = (warmBytesStored / (1024 * 1024 * 1024)) * cc.doStoragePerGBMonth;
1442
+ metrics.estimatedCost = { r2: r2Cost, do: doCost, cache: 0, total: r2Cost + doCost };
1443
+ }
1444
+ return metrics;
1445
+ }
1446
+ exportMetrics(format) {
1447
+ const metrics = this.getAggregatedMetrics();
1448
+ if (format === 'json')
1449
+ return metrics;
1450
+ const lines = [
1451
+ '# HELP tiered_storage_writes_total Total number of writes', '# TYPE tiered_storage_writes_total counter',
1452
+ `tiered_storage_writes_total{tier="hot"} ${metrics.tiers.hot.writes}`, `tiered_storage_writes_total{tier="warm"} ${metrics.tiers.warm.writes}`, `tiered_storage_writes_total{tier="cold"} ${metrics.tiers.cold.writes}`, '',
1453
+ '# HELP tiered_storage_bytes_written Total bytes written', '# TYPE tiered_storage_bytes_written counter',
1454
+ `tiered_storage_bytes_written{tier="hot"} ${metrics.tiers.hot.bytesWritten}`, `tiered_storage_bytes_written{tier="warm"} ${metrics.tiers.warm.bytesWritten}`, `tiered_storage_bytes_written{tier="cold"} ${metrics.tiers.cold.bytesWritten}`, '',
1455
+ '# HELP tiered_storage_reads_total Total number of reads', '# TYPE tiered_storage_reads_total counter',
1456
+ `tiered_storage_reads_total{tier="hot"} ${metrics.tiers.hot.reads}`, `tiered_storage_reads_total{tier="warm"} ${metrics.tiers.warm.reads}`, `tiered_storage_reads_total{tier="cold"} ${metrics.tiers.cold.reads}`, '',
1457
+ '# HELP tiered_storage_errors_total Total number of errors', '# TYPE tiered_storage_errors_total counter',
1458
+ `tiered_storage_errors_total{tier="hot"} ${metrics.errors.byTier.hot}`, `tiered_storage_errors_total{tier="warm"} ${metrics.errors.byTier.warm}`, `tiered_storage_errors_total{tier="cold"} ${metrics.errors.byTier.cold}`,
1459
+ ];
1460
+ return lines.join('\n');
1461
+ }
1462
+ // Component Integration
1463
+ createVFSInterface(_options) {
1464
+ return {
1465
+ readPage: async (pageId) => { const result = await this.read(pageId); return result.data; },
1466
+ writePage: async (pageId, data) => { await this.write(pageId, data); },
1467
+ deletePage: async (pageId) => { await this.delete(pageId); },
1468
+ };
1469
+ }
1470
+ configureAutoPromoter(config) {
1471
+ this.autoPromoterConfig = { ...config };
1472
+ this.config.coldToWarmThreshold = config.coldToWarm.accessThreshold;
1473
+ this.config.warmToHotThreshold = config.warmToHot.accessThreshold;
1474
+ if (config.warmToHot.timeWindowMs)
1475
+ this.config.promotionWindowMs = config.warmToHot.timeWindowMs;
1476
+ }
1477
+ getAutoPromoterConfig() { return { ...this.autoPromoterConfig }; }
1478
+ configureAutoDemoter(config) {
1479
+ this.autoDemoterConfig = { ...config };
1480
+ this.config.hotTtlMs = config.hotToWarm.ttlMs;
1481
+ this.config.warmTtlMs = config.warmToCold.ttlMs;
1482
+ }
1483
+ getAutoDemoterConfig() { return { ...this.autoDemoterConfig }; }
1484
+ setDemotionStrategy(tier, strategy) { this.demotionStrategies[tier] = strategy; }
1485
+ async runDemotionWithStrategy(tier, count) {
1486
+ const strategy = this.demotionStrategies[tier];
1487
+ if (!strategy) {
1488
+ if (tier === 'hot')
1489
+ return this.evictLRUFromHot(count);
1490
+ return [];
1491
+ }
1492
+ const entries = [];
1493
+ for (const entry of this.storageIndex.values()) {
1494
+ if (entry.tier === tier)
1495
+ entries.push(entry);
1496
+ }
1497
+ const keysToDemote = strategy(entries, count);
1498
+ const events = [];
1499
+ for (const key of keysToDemote) {
1500
+ const event = tier === 'hot' ? await this.demoteFromHot(key, 'lru_eviction') : await this.demoteFromWarm(key, 'lru_eviction');
1501
+ events.push(event);
1502
+ }
1503
+ return events;
1504
+ }
1505
+ // Error Recovery
1506
+ async runConsistencyCheck() {
1507
+ const repairs = [];
1508
+ for (const [key, entry] of this.storageIndex) {
1509
+ let found = false, actualTier;
1510
+ const warmData = await this.doStorage.get(this.doKey(key));
1511
+ if (warmData) {
1512
+ found = true;
1513
+ actualTier = 'warm';
1514
+ }
1515
+ if (!found) {
1516
+ const coldData = await this.r2Layer.get(key);
1517
+ if (coldData) {
1518
+ found = true;
1519
+ actualTier = 'cold';
1520
+ }
1521
+ }
1522
+ if (!found) {
1523
+ repairs.push({ key, issue: `Data not found in ${entry.tier} tier`, action: 'removed from index' });
1524
+ this.storageIndex.delete(key);
1525
+ }
1526
+ else if (actualTier && actualTier !== entry.tier && entry.tier !== 'hot') {
1527
+ repairs.push({ key, issue: `Index says ${entry.tier} but found in ${actualTier}`, action: `updated tier to ${actualTier}` });
1528
+ entry.tier = actualTier;
1529
+ }
1530
+ }
1531
+ return { inconsistencies: repairs.length, repairs };
1532
+ }
1533
+ // Advanced Tier Management
1534
+ setIndexEntryTimestamp(key, field, timestamp) {
1535
+ const entry = this.storageIndex.get(key);
1536
+ if (entry)
1537
+ entry[field] = timestamp;
1538
+ }
1539
+ getAccessPatternMetrics(key) {
1540
+ const entry = this.storageIndex.get(key);
1541
+ if (!entry)
1542
+ return { isBurst: false, accessRate: 0, recentAccesses: 0 };
1543
+ const ageMs = Math.max(1, Date.now() - entry.created);
1544
+ const accessRate = (entry.accessCount / ageMs) * 1000;
1545
+ return { isBurst: accessRate > 5, accessRate, recentAccesses: entry.accessCount };
1546
+ }
1547
+ async evictByMemoryPressure(bytesToFree) {
1548
+ const events = [];
1549
+ let freedBytes = 0;
1550
+ const hotEntries = Array.from(this.storageIndex.values()).filter(e => e.tier === 'hot').sort((a, b) => b.size - a.size);
1551
+ for (const entry of hotEntries) {
1552
+ if (freedBytes >= bytesToFree)
1553
+ break;
1554
+ const event = await this.demoteFromHot(entry.key, 'lru_eviction');
1555
+ events.push(event);
1556
+ if (event.success)
1557
+ freedBytes += entry.size;
1558
+ }
1559
+ return events;
1560
+ }
1561
+ setEntryPriority(key, priority) { this.entryPriorities.set(key, priority); }
1562
+ getEntryPriority(key) { return this.entryPriorities.get(key) ?? 'normal'; }
1563
+ async batchPromoteToWarm(keys) { return Promise.all(keys.map(key => this.promoteToWarm(key))); }
1564
+ async batchDemoteFromWarm(keys) { return Promise.all(keys.map(key => this.demoteFromWarm(key))); }
1565
+ async healthCheck() {
1566
+ const checkTier = async (tier) => {
1567
+ const start = Date.now();
1568
+ try {
1569
+ if (tier === 'hot')
1570
+ return { status: this.cacheLayer || this.swrCacheLayer ? 'healthy' : 'unavailable', latency: Date.now() - start };
1571
+ if (tier === 'warm') {
1572
+ await this.doStorage.get('__health_check__');
1573
+ return { status: 'healthy', latency: Date.now() - start };
1574
+ }
1575
+ await this.r2Layer.get('__health_check__');
1576
+ return { status: 'healthy', latency: Date.now() - start };
1577
+ }
1578
+ catch (e) {
1579
+ return { status: 'unhealthy', latency: Date.now() - start, error: e instanceof Error ? e.message : String(e) };
1580
+ }
1581
+ };
1582
+ const [hot, warm, cold] = await Promise.all([checkTier('hot'), checkTier('warm'), checkTier('cold')]);
1583
+ const statuses = [hot.status, warm.status, cold.status];
1584
+ let overall = 'healthy';
1585
+ if (statuses.some(s => s === 'unhealthy'))
1586
+ overall = 'degraded';
1587
+ if (statuses.every(s => s === 'unhealthy'))
1588
+ overall = 'unhealthy';
1589
+ return { overall, tiers: { hot, warm, cold }, latency: { hot: hot.latency, warm: warm.latency, cold: cold.latency } };
1590
+ }
1591
+ getMemoryUsage() {
1592
+ let hot = 0, warm = 0, cold = 0;
1593
+ for (const entry of this.storageIndex.values()) {
1594
+ if (entry.tier === 'hot')
1595
+ hot += entry.size;
1596
+ else if (entry.tier === 'warm')
1597
+ warm += entry.size;
1598
+ else
1599
+ cold += entry.size;
1600
+ }
1601
+ const total = hot + warm + cold;
1602
+ const limit = (this.memoryLimits.hot ?? Infinity) + (this.memoryLimits.warm ?? Infinity);
1603
+ return { hot, warm, cold, total, limit, utilizationPercent: limit === Infinity ? 0 : (total / limit) * 100 };
1604
+ }
1605
+ setMemoryLimit(limits) { this.memoryLimits = { ...this.memoryLimits, ...limits }; }
1606
+ getMemoryLimits() { return { ...this.memoryLimits }; }
1607
+ async prefetch(keys, options) {
1608
+ const targetTier = options?.targetTier ?? 'warm';
1609
+ const maxConcurrency = options?.maxConcurrency ?? 5;
1610
+ const failedKeys = [];
1611
+ let prefetchedCount = 0;
1612
+ for (let i = 0; i < keys.length; i += maxConcurrency) {
1613
+ const batch = keys.slice(i, i + maxConcurrency);
1614
+ const results = await Promise.allSettled(batch.map(async (key) => {
1615
+ const event = targetTier === 'hot' ? await this.promoteToHot(key) : await this.promoteToWarm(key);
1616
+ if (!event.success)
1617
+ throw new Error(event.error);
1618
+ return key;
1619
+ }));
1620
+ for (let j = 0; j < results.length; j++) {
1621
+ const result = results[j];
1622
+ if (result?.status === 'fulfilled')
1623
+ prefetchedCount++;
1624
+ else if (result?.status === 'rejected' && batch[j])
1625
+ failedKeys.push(batch[j]);
1626
+ }
1627
+ }
1628
+ return { prefetchedCount, failedKeys };
1629
+ }
1630
+ subscribeToEvents(callback, options) {
1631
+ const subscriber = { callback, filter: options?.filter };
1632
+ this.eventSubscribers.push(subscriber);
1633
+ return () => { const idx = this.eventSubscribers.indexOf(subscriber); if (idx !== -1)
1634
+ this.eventSubscribers.splice(idx, 1); };
1635
+ }
1636
+ async createSnapshot() {
1637
+ return { version: 1, timestamp: Date.now(), index: Array.from(this.storageIndex.values()), stats: this.getStats() };
1638
+ }
1639
+ async restoreFromSnapshot(snapshot) {
1640
+ this.storageIndex.clear();
1641
+ this.indexMemoryBytes = 0;
1642
+ for (const entry of snapshot.index) {
1643
+ this.storageIndex.set(entry.key, { ...entry });
1644
+ this.indexMemoryBytes += TieredStorageOrchestrator.ENTRY_MEMORY_OVERHEAD + entry.key.length * 2;
1645
+ }
1646
+ }
1647
+ async warmup(options) {
1648
+ let candidates = Array.from(this.storageIndex.values()).filter(e => e.tier === 'cold');
1649
+ if (options.strategy === 'most-accessed')
1650
+ candidates.sort((a, b) => b.accessCount - a.accessCount);
1651
+ else if (options.strategy === 'recent')
1652
+ candidates.sort((a, b) => b.lastAccess - a.lastAccess);
1653
+ if (options.limit)
1654
+ candidates = candidates.slice(0, options.limit);
1655
+ let bytesTransferred = 0;
1656
+ const warmedKeys = [];
1657
+ for (const entry of candidates) {
1658
+ if (options.maxBytes && bytesTransferred + entry.size > options.maxBytes)
1659
+ break;
1660
+ const event = options.targetTier === 'hot' ? await this.promoteToHot(entry.key) : await this.promoteToWarm(entry.key);
1661
+ if (event.success) {
1662
+ bytesTransferred += entry.size;
1663
+ warmedKeys.push(entry.key);
1664
+ }
1665
+ }
1666
+ return { warmedUp: warmedKeys.length, bytesTransferred, keys: warmedKeys };
1667
+ }
1668
+ async garbageCollect(options) {
1669
+ let removedEntries = 0;
1670
+ const keysToRemove = [];
1671
+ for (const [key, entry] of this.storageIndex) {
1672
+ if (entry.tier === 'hot')
1673
+ continue;
1674
+ let exists = false;
1675
+ if (entry.tier === 'warm') {
1676
+ const data = await this.doStorage.get(this.doKey(key));
1677
+ exists = !!data;
1678
+ }
1679
+ else {
1680
+ const data = await this.r2Layer.get(key);
1681
+ exists = !!data;
1682
+ }
1683
+ if (!exists)
1684
+ keysToRemove.push(key);
1685
+ }
1686
+ for (const key of keysToRemove) {
1687
+ this.storageIndex.delete(key);
1688
+ removedEntries++;
1689
+ }
1690
+ return options?.compactCold ? { removedEntries, compactionStats: { bytesReclaimed: 0 } } : { removedEntries };
1691
+ }
1692
+ pinToTier(key, _tier) { this.pinnedEntries.add(key); }
1693
+ unpinFromTier(key) { this.pinnedEntries.delete(key); }
1694
+ isPinned(key) { return this.pinnedEntries.has(key); }
1695
+ getCostBreakdown() {
1696
+ const metrics = this.getAggregatedMetrics();
1697
+ const cc = this.config.metrics?.costConfig ?? { r2StoragePerGBMonth: 0.015, r2ClassAOperations: 0.0000045, r2ClassBOperations: 0.00000036, doStoragePerGBMonth: 0.20, cacheOperations: 0 };
1698
+ const r2Storage = (metrics.tiers.cold.bytesStored / (1024 ** 3)) * cc.r2StoragePerGBMonth;
1699
+ const doStorage = (metrics.tiers.warm.bytesStored / (1024 ** 3)) * cc.doStoragePerGBMonth;
1700
+ const r2Writes = metrics.tiers.cold.writes * cc.r2ClassAOperations;
1701
+ const r2Reads = metrics.tiers.cold.reads * cc.r2ClassBOperations;
1702
+ const total = r2Storage + doStorage + r2Writes + r2Reads;
1703
+ return { storage: { r2: r2Storage, do: doStorage, cache: 0 }, operations: { r2Writes, r2Reads, doWrites: 0, doReads: 0 }, total, projectedMonthly: total };
1704
+ }
1705
+ async optimizeTierPlacement() {
1706
+ const promotions = [];
1707
+ const demotions = [];
1708
+ for (const entry of this.storageIndex.values()) {
1709
+ if (entry.tier === 'cold' && entry.accessCount > 10)
1710
+ promotions.push({ key: entry.key, currentTier: 'cold', suggestedTier: 'warm', reason: 'High access count' });
1711
+ if (entry.tier === 'warm' && entry.accessCount < 5 && Date.now() - entry.lastAccess > 86400000)
1712
+ demotions.push({ key: entry.key, currentTier: 'warm', suggestedTier: 'cold', reason: 'Low access, stale' });
1713
+ }
1714
+ return { promotions, demotions, estimatedSavings: 0 };
1715
+ }
1716
+ async ensureDurability(key) {
1717
+ const coldData = await this.r2Layer.get(key);
1718
+ if (coldData)
1719
+ return { durable: true, tier: 'cold', copied: false };
1720
+ const warmData = await this.doStorage.get(this.doKey(key));
1721
+ if (warmData) {
1722
+ await this.r2Layer.put(key, warmData, { customMetadata: { durabilityBackup: 'true' } });
1723
+ return { durable: true, tier: 'warm', copied: true };
1724
+ }
1725
+ return { durable: false, tier: null, copied: false };
1726
+ }
1727
+ }
1728
+ export function createTieredStorageOrchestrator(config) {
1729
+ return new TieredStorageOrchestrator(config);
1730
+ }
1731
+ //# sourceMappingURL=tiered-orchestrator.js.map