@pithy-sh/core 0.1.2 → 0.1.4

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 (393) hide show
  1. package/dist/address/address.d.ts +57 -0
  2. package/dist/address/address.d.ts.map +1 -0
  3. package/dist/address/address.js +71 -0
  4. package/dist/audit/auditEvent.d.ts +89 -0
  5. package/dist/audit/auditEvent.d.ts.map +1 -0
  6. package/dist/audit/auditEvent.js +69 -0
  7. package/dist/audit/recorder.d.ts +18 -0
  8. package/dist/audit/recorder.d.ts.map +1 -0
  9. package/dist/audit/recorder.js +8 -0
  10. package/dist/capability/bindings.d.ts +62 -0
  11. package/dist/capability/bindings.d.ts.map +1 -0
  12. package/dist/capability/bindings.js +97 -0
  13. package/dist/capability/capability.d.ts +501 -0
  14. package/dist/capability/capability.d.ts.map +1 -0
  15. package/dist/capability/capability.js +16 -0
  16. package/dist/capability/client.d.ts +70 -0
  17. package/dist/capability/client.d.ts.map +1 -0
  18. package/dist/capability/client.js +86 -0
  19. package/dist/capability/compose.d.ts +25 -0
  20. package/dist/capability/compose.d.ts.map +1 -0
  21. package/dist/capability/compose.js +54 -0
  22. package/dist/capability/composition.d.ts +26 -0
  23. package/dist/capability/composition.d.ts.map +1 -0
  24. package/dist/capability/composition.js +84 -0
  25. package/dist/capability/config.d.ts +7 -0
  26. package/dist/capability/config.d.ts.map +1 -0
  27. package/dist/capability/config.js +14 -0
  28. package/dist/capability/devSecret.d.ts +32 -0
  29. package/dist/capability/devSecret.d.ts.map +1 -0
  30. package/dist/capability/devSecret.js +28 -0
  31. package/dist/capability/manifest.d.ts +298 -0
  32. package/dist/capability/manifest.d.ts.map +1 -0
  33. package/dist/capability/manifest.js +356 -0
  34. package/dist/capability/secretOrigin.d.ts +121 -0
  35. package/dist/capability/secretOrigin.d.ts.map +1 -0
  36. package/dist/capability/secretOrigin.js +134 -0
  37. package/dist/capability/settings.d.ts +119 -0
  38. package/dist/capability/settings.d.ts.map +1 -0
  39. package/dist/capability/settings.js +66 -0
  40. package/dist/capability/validateBindings.d.ts +4 -0
  41. package/dist/capability/validateBindings.d.ts.map +1 -0
  42. package/dist/capability/validateBindings.js +34 -0
  43. package/dist/capability/vanishingKey.d.ts +31 -0
  44. package/dist/capability/vanishingKey.d.ts.map +1 -0
  45. package/dist/capability/vanishingKey.js +79 -0
  46. package/dist/controlPlane/audit/actions.d.ts +70 -0
  47. package/dist/controlPlane/audit/actions.d.ts.map +1 -0
  48. package/dist/controlPlane/audit/actions.js +76 -0
  49. package/dist/controlPlane/capability.d.ts +47 -0
  50. package/dist/controlPlane/capability.d.ts.map +1 -0
  51. package/dist/controlPlane/capability.js +138 -0
  52. package/dist/controlPlane/config/config.d.ts +19 -0
  53. package/dist/controlPlane/config/config.d.ts.map +1 -0
  54. package/dist/controlPlane/config/config.js +85 -0
  55. package/dist/controlPlane/context.d.ts +27 -0
  56. package/dist/controlPlane/context.d.ts.map +1 -0
  57. package/dist/controlPlane/context.js +29 -0
  58. package/dist/controlPlane/data/connection.d.ts +79 -0
  59. package/dist/controlPlane/data/connection.d.ts.map +1 -0
  60. package/dist/controlPlane/data/connection.js +55 -0
  61. package/dist/controlPlane/data/keyLifecycle.d.ts +62 -0
  62. package/dist/controlPlane/data/keyLifecycle.d.ts.map +1 -0
  63. package/dist/controlPlane/data/keyLifecycle.js +126 -0
  64. package/dist/controlPlane/data/replay.d.ts +18 -0
  65. package/dist/controlPlane/data/replay.d.ts.map +1 -0
  66. package/dist/controlPlane/data/replay.js +20 -0
  67. package/dist/controlPlane/data/tables.d.ts +34 -0
  68. package/dist/controlPlane/data/tables.d.ts.map +1 -0
  69. package/dist/controlPlane/data/tables.js +37 -0
  70. package/dist/controlPlane/discovery/adminRoute.d.ts +313 -0
  71. package/dist/controlPlane/discovery/adminRoute.d.ts.map +1 -0
  72. package/dist/controlPlane/discovery/adminRoute.js +136 -0
  73. package/dist/controlPlane/discovery/configuration.d.ts +108 -0
  74. package/dist/controlPlane/discovery/configuration.d.ts.map +1 -0
  75. package/dist/controlPlane/discovery/configuration.js +187 -0
  76. package/dist/controlPlane/discovery/drift.d.ts +64 -0
  77. package/dist/controlPlane/discovery/drift.d.ts.map +1 -0
  78. package/dist/controlPlane/discovery/drift.js +58 -0
  79. package/dist/controlPlane/discovery/health.d.ts +99 -0
  80. package/dist/controlPlane/discovery/health.d.ts.map +1 -0
  81. package/dist/controlPlane/discovery/health.js +151 -0
  82. package/dist/controlPlane/discovery/healthSummary.d.ts +236 -0
  83. package/dist/controlPlane/discovery/healthSummary.d.ts.map +1 -0
  84. package/dist/controlPlane/discovery/healthSummary.js +278 -0
  85. package/dist/controlPlane/error/errors.d.ts +67 -0
  86. package/dist/controlPlane/error/errors.d.ts.map +1 -0
  87. package/dist/controlPlane/error/errors.js +79 -0
  88. package/dist/controlPlane/http/cors.d.ts +112 -0
  89. package/dist/controlPlane/http/cors.d.ts.map +1 -0
  90. package/dist/controlPlane/http/cors.js +192 -0
  91. package/dist/controlPlane/http/guard.d.ts +77 -0
  92. package/dist/controlPlane/http/guard.d.ts.map +1 -0
  93. package/dist/controlPlane/http/guard.js +142 -0
  94. package/dist/controlPlane/http/handlers.d.ts +179 -0
  95. package/dist/controlPlane/http/handlers.d.ts.map +1 -0
  96. package/dist/controlPlane/http/handlers.js +245 -0
  97. package/dist/controlPlane/http/responses.d.ts +99 -0
  98. package/dist/controlPlane/http/responses.d.ts.map +1 -0
  99. package/dist/controlPlane/http/responses.js +63 -0
  100. package/dist/controlPlane/http/routes.d.ts +40 -0
  101. package/dist/controlPlane/http/routes.d.ts.map +1 -0
  102. package/dist/controlPlane/http/routes.js +83 -0
  103. package/dist/controlPlane/http/schemas.d.ts +39 -0
  104. package/dist/controlPlane/http/schemas.d.ts.map +1 -0
  105. package/dist/controlPlane/http/schemas.js +31 -0
  106. package/dist/controlPlane/http/verify.d.ts +84 -0
  107. package/dist/controlPlane/http/verify.d.ts.map +1 -0
  108. package/dist/controlPlane/http/verify.js +65 -0
  109. package/dist/controlPlane/migrations/0001_init.d.ts +51 -0
  110. package/dist/controlPlane/migrations/0001_init.d.ts.map +1 -0
  111. package/dist/controlPlane/migrations/0001_init.js +65 -0
  112. package/dist/controlPlane/replay/d1Guard.d.ts +29 -0
  113. package/dist/controlPlane/replay/d1Guard.d.ts.map +1 -0
  114. package/dist/controlPlane/replay/d1Guard.js +39 -0
  115. package/dist/controlPlane/replay/guard.d.ts +52 -0
  116. package/dist/controlPlane/replay/guard.d.ts.map +1 -0
  117. package/dist/controlPlane/replay/guard.js +0 -0
  118. package/dist/controlPlane/replay/kvGuard.d.ts +99 -0
  119. package/dist/controlPlane/replay/kvGuard.d.ts.map +1 -0
  120. package/dist/controlPlane/replay/kvGuard.js +101 -0
  121. package/dist/controlPlane/scope/scope.d.ts +68 -0
  122. package/dist/controlPlane/scope/scope.d.ts.map +1 -0
  123. package/dist/controlPlane/scope/scope.js +63 -0
  124. package/dist/controlPlane/token/base64url.d.ts +10 -0
  125. package/dist/controlPlane/token/base64url.d.ts.map +1 -0
  126. package/dist/controlPlane/token/base64url.js +48 -0
  127. package/dist/controlPlane/token/claims.d.ts +83 -0
  128. package/dist/controlPlane/token/claims.d.ts.map +1 -0
  129. package/dist/controlPlane/token/claims.js +86 -0
  130. package/dist/controlPlane/token/digest.d.ts +44 -0
  131. package/dist/controlPlane/token/digest.d.ts.map +1 -0
  132. package/dist/controlPlane/token/digest.js +56 -0
  133. package/dist/controlPlane/token/jws.d.ts +52 -0
  134. package/dist/controlPlane/token/jws.d.ts.map +1 -0
  135. package/dist/controlPlane/token/jws.js +65 -0
  136. package/dist/controlPlane/token/mint.d.ts +56 -0
  137. package/dist/controlPlane/token/mint.d.ts.map +1 -0
  138. package/dist/controlPlane/token/mint.js +55 -0
  139. package/dist/controlPlane/wire.d.ts +122 -0
  140. package/dist/controlPlane/wire.d.ts.map +1 -0
  141. package/dist/controlPlane/wire.js +123 -0
  142. package/dist/createBackend.d.ts +58 -0
  143. package/dist/createBackend.d.ts.map +1 -0
  144. package/dist/createBackend.js +170 -0
  145. package/dist/createEntrypoint.d.ts +53 -0
  146. package/dist/createEntrypoint.d.ts.map +1 -0
  147. package/dist/createEntrypoint.js +52 -0
  148. package/dist/data/boundParameters.d.ts +83 -0
  149. package/dist/data/boundParameters.d.ts.map +1 -0
  150. package/dist/data/boundParameters.js +162 -0
  151. package/dist/data/codecs.d.ts +34 -0
  152. package/dist/data/codecs.d.ts.map +1 -0
  153. package/dist/data/codecs.js +135 -0
  154. package/dist/data/cursor.d.ts +81 -0
  155. package/dist/data/cursor.d.ts.map +1 -0
  156. package/dist/data/cursor.js +104 -0
  157. package/dist/data/databases.d.ts +55 -0
  158. package/dist/data/databases.d.ts.map +1 -0
  159. package/dist/data/databases.js +32 -0
  160. package/dist/data/db.d.ts +42 -0
  161. package/dist/data/db.d.ts.map +1 -0
  162. package/dist/data/db.js +24 -0
  163. package/dist/data/withD1Retry.d.ts +91 -0
  164. package/dist/data/withD1Retry.d.ts.map +1 -0
  165. package/dist/data/withD1Retry.js +152 -0
  166. package/dist/entitlement/entitlement.d.ts +118 -0
  167. package/dist/entitlement/entitlement.d.ts.map +1 -0
  168. package/dist/entitlement/entitlement.js +59 -0
  169. package/dist/entitlement/gateScan.d.ts +26 -0
  170. package/dist/entitlement/gateScan.d.ts.map +1 -0
  171. package/dist/entitlement/gateScan.js +96 -0
  172. package/dist/entitlement/require.d.ts +12 -0
  173. package/dist/entitlement/require.d.ts.map +1 -0
  174. package/dist/entitlement/require.js +123 -0
  175. package/dist/env/ambient.d.ts +52 -0
  176. package/dist/env/ambient.d.ts.map +1 -0
  177. package/dist/env/ambient.js +35 -0
  178. package/dist/env/ci.d.ts +36 -0
  179. package/dist/env/ci.d.ts.map +1 -0
  180. package/dist/env/ci.js +40 -0
  181. package/dist/env/stem.d.ts +23 -0
  182. package/dist/env/stem.d.ts.map +1 -0
  183. package/dist/env/stem.js +29 -0
  184. package/dist/error/cause.d.ts +143 -0
  185. package/dist/error/cause.d.ts.map +1 -0
  186. package/dist/error/cause.js +192 -0
  187. package/dist/error/client.d.ts +35 -0
  188. package/dist/error/client.d.ts.map +1 -0
  189. package/dist/error/client.js +38 -0
  190. package/dist/error/extend.d.ts +101 -0
  191. package/dist/error/extend.d.ts.map +1 -0
  192. package/dist/error/extend.js +76 -0
  193. package/dist/error/http.d.ts +1516 -0
  194. package/dist/error/http.d.ts.map +1 -0
  195. package/dist/error/http.js +72 -0
  196. package/dist/error/payload.d.ts +3034 -0
  197. package/dist/error/payload.d.ts.map +1 -0
  198. package/dist/error/payload.js +1110 -0
  199. package/dist/error/pithyError.d.ts +154 -0
  200. package/dist/error/pithyError.d.ts.map +1 -0
  201. package/dist/error/pithyError.js +197 -0
  202. package/dist/error/terminal.d.ts +28 -0
  203. package/dist/error/terminal.d.ts.map +1 -0
  204. package/dist/error/terminal.js +33 -0
  205. package/dist/http/authContext.d.ts +21 -0
  206. package/dist/http/authContext.d.ts.map +1 -0
  207. package/dist/http/authContext.js +23 -0
  208. package/dist/http/routeContract.d.ts +39 -0
  209. package/dist/http/routeContract.d.ts.map +1 -0
  210. package/dist/http/routeContract.js +82 -0
  211. package/dist/http/sameOrigin.d.ts +47 -0
  212. package/dist/http/sameOrigin.d.ts.map +1 -0
  213. package/dist/http/sameOrigin.js +24 -0
  214. package/dist/http/signedWebhook.d.ts +225 -0
  215. package/dist/http/signedWebhook.d.ts.map +1 -0
  216. package/dist/http/signedWebhook.js +247 -0
  217. package/dist/http/validation.d.ts +37 -0
  218. package/dist/http/validation.d.ts.map +1 -0
  219. package/dist/http/validation.js +14 -0
  220. package/dist/http/verification.d.ts +10 -0
  221. package/dist/http/verification.d.ts.map +1 -0
  222. package/dist/http/verification.js +17 -0
  223. package/dist/i18n/acceptLanguage.d.ts +22 -0
  224. package/dist/i18n/acceptLanguage.d.ts.map +1 -0
  225. package/dist/i18n/acceptLanguage.js +55 -0
  226. package/dist/i18n/catalog.d.ts +39 -0
  227. package/dist/i18n/catalog.d.ts.map +1 -0
  228. package/dist/i18n/catalog.js +57 -0
  229. package/dist/i18n/locale.d.ts +74 -0
  230. package/dist/i18n/locale.d.ts.map +1 -0
  231. package/dist/i18n/locale.js +109 -0
  232. package/dist/i18n/localeMarker.d.ts +29 -0
  233. package/dist/i18n/localeMarker.d.ts.map +1 -0
  234. package/dist/i18n/localeMarker.js +112 -0
  235. package/dist/i18n/match.d.ts +26 -0
  236. package/dist/i18n/match.d.ts.map +1 -0
  237. package/dist/i18n/match.js +88 -0
  238. package/dist/i18n/registry.d.ts +25 -0
  239. package/dist/i18n/registry.d.ts.map +1 -0
  240. package/dist/i18n/registry.js +51 -0
  241. package/dist/i18n/translator.d.ts +107 -0
  242. package/dist/i18n/translator.d.ts.map +1 -0
  243. package/dist/i18n/translator.js +80 -0
  244. package/dist/index.d.ts +32 -0
  245. package/dist/index.d.ts.map +1 -0
  246. package/dist/index.js +17 -0
  247. package/dist/kv/kv.d.ts +166 -0
  248. package/dist/kv/kv.d.ts.map +1 -0
  249. package/dist/kv/kv.js +261 -0
  250. package/dist/kv/namespaces.d.ts +58 -0
  251. package/dist/kv/namespaces.d.ts.map +1 -0
  252. package/dist/kv/namespaces.js +40 -0
  253. package/dist/logger/local.d.ts +41 -0
  254. package/dist/logger/local.d.ts.map +1 -0
  255. package/dist/logger/local.js +45 -0
  256. package/dist/logger/logger.d.ts +56 -0
  257. package/dist/logger/logger.d.ts.map +1 -0
  258. package/dist/logger/logger.js +83 -0
  259. package/dist/logger/record.d.ts +919 -0
  260. package/dist/logger/record.d.ts.map +1 -0
  261. package/dist/logger/record.js +79 -0
  262. package/dist/logger/worker.d.ts +74 -0
  263. package/dist/logger/worker.d.ts.map +1 -0
  264. package/dist/logger/worker.js +54 -0
  265. package/dist/migrations/batch.d.ts +10 -0
  266. package/dist/migrations/batch.d.ts.map +1 -0
  267. package/dist/migrations/batch.js +193 -0
  268. package/dist/migrations/bookkeeping.d.ts +24 -0
  269. package/dist/migrations/bookkeeping.d.ts.map +1 -0
  270. package/dist/migrations/bookkeeping.js +57 -0
  271. package/dist/migrations/owner.d.ts +41 -0
  272. package/dist/migrations/owner.d.ts.map +1 -0
  273. package/dist/migrations/owner.js +105 -0
  274. package/dist/migrations/registry.d.ts +36 -0
  275. package/dist/migrations/registry.d.ts.map +1 -0
  276. package/dist/migrations/registry.js +70 -0
  277. package/dist/migrations/runner.d.ts +67 -0
  278. package/dist/migrations/runner.d.ts.map +1 -0
  279. package/dist/migrations/runner.js +218 -0
  280. package/dist/naming/domains.d.ts +108 -0
  281. package/dist/naming/domains.d.ts.map +1 -0
  282. package/dist/naming/domains.js +156 -0
  283. package/dist/naming/environment.d.ts +118 -0
  284. package/dist/naming/environment.d.ts.map +1 -0
  285. package/dist/naming/environment.js +190 -0
  286. package/dist/naming/feature.d.ts +68 -0
  287. package/dist/naming/feature.d.ts.map +1 -0
  288. package/dist/naming/feature.js +106 -0
  289. package/dist/naming/limits.d.ts +229 -0
  290. package/dist/naming/limits.d.ts.map +1 -0
  291. package/dist/naming/limits.js +187 -0
  292. package/dist/naming/provisionScope.d.ts +91 -0
  293. package/dist/naming/provisionScope.d.ts.map +1 -0
  294. package/dist/naming/provisionScope.js +65 -0
  295. package/dist/naming/resource.d.ts +169 -0
  296. package/dist/naming/resource.d.ts.map +1 -0
  297. package/dist/naming/resource.js +220 -0
  298. package/dist/naming/resourceNames.d.ts +83 -0
  299. package/dist/naming/resourceNames.d.ts.map +1 -0
  300. package/dist/naming/resourceNames.js +102 -0
  301. package/dist/naming/segment.d.ts +29 -0
  302. package/dist/naming/segment.d.ts.map +1 -0
  303. package/dist/naming/segment.js +31 -0
  304. package/dist/projection/asRead.d.ts +72 -0
  305. package/dist/projection/asRead.d.ts.map +1 -0
  306. package/dist/projection/asRead.js +169 -0
  307. package/dist/projection/published.d.ts +95 -0
  308. package/dist/projection/published.d.ts.map +1 -0
  309. package/dist/projection/published.js +114 -0
  310. package/dist/schema/describedness.d.ts +55 -0
  311. package/dist/schema/describedness.d.ts.map +1 -0
  312. package/dist/schema/describedness.js +180 -0
  313. package/dist/seed/compose.d.ts +41 -0
  314. package/dist/seed/compose.d.ts.map +1 -0
  315. package/dist/seed/compose.js +51 -0
  316. package/dist/seed/devLogin.d.ts +50 -0
  317. package/dist/seed/devLogin.d.ts.map +1 -0
  318. package/dist/seed/devLogin.js +52 -0
  319. package/dist/seed/exampleIdentities.d.ts +58 -0
  320. package/dist/seed/exampleIdentities.d.ts.map +1 -0
  321. package/dist/seed/exampleIdentities.js +26 -0
  322. package/dist/seed/metadata.d.ts +20 -0
  323. package/dist/seed/metadata.d.ts.map +1 -0
  324. package/dist/seed/metadata.js +27 -0
  325. package/dist/seed/seed.d.ts +264 -0
  326. package/dist/seed/seed.d.ts.map +1 -0
  327. package/dist/seed/seed.js +37 -0
  328. package/dist/seed/seededRows.d.ts +26 -0
  329. package/dist/seed/seededRows.d.ts.map +1 -0
  330. package/dist/seed/seededRows.js +20 -0
  331. package/dist/seed/writeD1.d.ts +43 -0
  332. package/dist/seed/writeD1.d.ts.map +1 -0
  333. package/dist/seed/writeD1.js +73 -0
  334. package/dist/seed/writeKv.d.ts +29 -0
  335. package/dist/seed/writeKv.d.ts.map +1 -0
  336. package/dist/seed/writeKv.js +63 -0
  337. package/dist/semver/semver.d.ts +62 -0
  338. package/dist/semver/semver.d.ts.map +1 -0
  339. package/dist/semver/semver.js +137 -0
  340. package/dist/text/comments.d.ts +62 -0
  341. package/dist/text/comments.d.ts.map +1 -0
  342. package/dist/text/comments.js +161 -0
  343. package/dist/version.generated.d.ts +5 -0
  344. package/dist/version.generated.d.ts.map +1 -0
  345. package/dist/version.generated.js +7 -0
  346. package/dist/worker/health.d.ts +39 -0
  347. package/dist/worker/health.d.ts.map +1 -0
  348. package/dist/worker/health.js +41 -0
  349. package/dist/worker/identity.d.ts +191 -0
  350. package/dist/worker/identity.d.ts.map +1 -0
  351. package/dist/worker/identity.js +162 -0
  352. package/dist/workflow/bindings.d.ts +41 -0
  353. package/dist/workflow/bindings.d.ts.map +1 -0
  354. package/dist/workflow/bindings.js +53 -0
  355. package/dist/workflow/dispatch.d.ts +98 -0
  356. package/dist/workflow/dispatch.d.ts.map +1 -0
  357. package/dist/workflow/dispatch.js +148 -0
  358. package/dist/workflow/dispatchRoute.d.ts +80 -0
  359. package/dist/workflow/dispatchRoute.d.ts.map +1 -0
  360. package/dist/workflow/dispatchRoute.js +134 -0
  361. package/dist/workflow/faults.d.ts +97 -0
  362. package/dist/workflow/faults.d.ts.map +1 -0
  363. package/dist/workflow/faults.js +111 -0
  364. package/dist/workflow/host.d.ts +176 -0
  365. package/dist/workflow/host.d.ts.map +1 -0
  366. package/dist/workflow/host.js +116 -0
  367. package/dist/workflow/hostEntry.d.ts +50 -0
  368. package/dist/workflow/hostEntry.d.ts.map +1 -0
  369. package/dist/workflow/hostEntry.js +24 -0
  370. package/dist/workflow/hostEnv.d.ts +143 -0
  371. package/dist/workflow/hostEnv.d.ts.map +1 -0
  372. package/dist/workflow/hostEnv.js +170 -0
  373. package/dist/workflow/loopback.d.ts +52 -0
  374. package/dist/workflow/loopback.d.ts.map +1 -0
  375. package/dist/workflow/loopback.js +76 -0
  376. package/dist/workflow/naming.d.ts +79 -0
  377. package/dist/workflow/naming.d.ts.map +1 -0
  378. package/dist/workflow/naming.js +138 -0
  379. package/dist/workflow/register.d.ts +19 -0
  380. package/dist/workflow/register.d.ts.map +1 -0
  381. package/dist/workflow/register.js +40 -0
  382. package/dist/workflow/schemas.d.ts +44 -0
  383. package/dist/workflow/schemas.d.ts.map +1 -0
  384. package/dist/workflow/schemas.js +43 -0
  385. package/dist/workflow/spec.d.ts +81 -0
  386. package/dist/workflow/spec.d.ts.map +1 -0
  387. package/dist/workflow/spec.js +0 -0
  388. package/dist/workflow/stepMessage.d.ts +122 -0
  389. package/dist/workflow/stepMessage.d.ts.map +1 -0
  390. package/dist/workflow/stepMessage.js +152 -0
  391. package/package.json +20 -9
  392. package/src/capability/manifest.ts +21 -0
  393. package/src/version.generated.ts +1 -1
package/dist/kv/kv.js ADDED
@@ -0,0 +1,261 @@
1
+ import { InternalError, NotFoundError, messageOf } from "../error/pithyError.js";
2
+ import { noopLogger } from "../logger/logger.js";
3
+ //#region src/kv/kv.ts
4
+ /** Cloudflare's hard limit on a KV entry's metadata, in bytes. */
5
+ const KV_METADATA_MAX_BYTES = 1024;
6
+ const encoder = new TextEncoder();
7
+ function byteLength(value) {
8
+ return encoder.encode(value).length;
9
+ }
10
+ /**
11
+ * Wrap a metadata schema with KV's size limit.
12
+ *
13
+ * WARNING: metadata travels with **every** `list` entry and is capped at
14
+ * {@link KV_METADATA_MAX_BYTES} bytes serialized. It is for small, list-time
15
+ * fields you want without reading each value — a status flag, a type, a
16
+ * timestamp — never a payload. This refinement fails a value that would exceed
17
+ * the cap, turning a late KV rejection into an early, clear validation error.
18
+ */
19
+ function kvMetadata(schema) {
20
+ return schema.refine((value) => byteLength(JSON.stringify(value)) <= KV_METADATA_MAX_BYTES, { message: `KV metadata exceeds ${KV_METADATA_MAX_BYTES} bytes serialized. Keep it tiny — it rides on every list entry.` });
21
+ }
22
+ /**
23
+ * Validate a {@link TypedKvConfig} at construction — config is a boundary, so it
24
+ * is checked, not trusted. Catches the misconfigurations the type system can't
25
+ * (or won't, for JS callers and casts): an empty namespace, a separator that
26
+ * collides with the prefix, a key with no segments, `deriveMetadata` without a
27
+ * `metadata` schema to validate against, or a non-positive default TTL.
28
+ */
29
+ function assertValidConfig(config) {
30
+ if (config.prefix.length === 0) throw new InternalError({ message: "TypedKv config: prefix must be a non-empty capability namespace." });
31
+ const separator = config.separator ?? ":";
32
+ if (separator.length === 0) throw new InternalError({ message: "TypedKv config: separator must be a non-empty string." });
33
+ if (config.prefix.includes(separator)) throw new InternalError({ message: `TypedKv config: prefix "${config.prefix}" must not contain the separator "${separator}".` });
34
+ if (Object.keys(config.key.shape).length === 0) throw new InternalError({ message: "TypedKv config: key must declare at least one segment." });
35
+ if (config.deriveMetadata !== void 0 && config.metadata === void 0) throw new InternalError({ message: "TypedKv config: deriveMetadata requires a metadata schema to validate the derived value." });
36
+ if (config.ttlSeconds !== void 0 && config.ttlSeconds <= 0) throw new InternalError({ message: "TypedKv config: ttlSeconds must be positive." });
37
+ }
38
+ /**
39
+ * Typed, validated access to one Workers KV namespace.
40
+ *
41
+ * Keys are structured: a fixed capability `prefix` followed by ordered,
42
+ * Zod-validated segments — so a single store models `pages:<uuid>` or
43
+ * `assets:<assetType>:<uuid>` and `list` can scope by any leading run of those
44
+ * segments. Values are validated on the way in and out; there is no untyped
45
+ * `JSON.parse`. Metadata is validated too and rides along with `list`; with
46
+ * `deriveMetadata` the value is the source of truth and `list` rebuilds metadata
47
+ * that external edits have dropped.
48
+ */
49
+ var TypedKv = class {
50
+ #namespace;
51
+ #prefix;
52
+ #keySchema;
53
+ #valueSchema;
54
+ #metadataSchema;
55
+ #deriveMetadata;
56
+ #separator;
57
+ #defaultTtlSeconds;
58
+ #segmentNames;
59
+ #logger;
60
+ constructor(namespace, config, options) {
61
+ assertValidConfig(config);
62
+ this.#namespace = namespace;
63
+ this.#prefix = config.prefix;
64
+ this.#keySchema = config.key;
65
+ this.#valueSchema = config.value;
66
+ this.#metadataSchema = config.metadata;
67
+ this.#deriveMetadata = config.deriveMetadata;
68
+ this.#separator = config.separator ?? ":";
69
+ this.#defaultTtlSeconds = config.ttlSeconds;
70
+ this.#segmentNames = Object.keys(config.key.shape);
71
+ this.#logger = options?.logger ?? noopLogger;
72
+ }
73
+ /** Build the full physical KV key (name) from validated segments. */
74
+ name(key) {
75
+ const parsed = this.#keySchema.parse(key);
76
+ const segments = this.#segmentNames.map((segment) => this.#segment(segment, parsed[segment]));
77
+ return [this.#prefix, ...segments].join(this.#separator);
78
+ }
79
+ /**
80
+ * Read and validate the value at `key`. Returns `null` on a miss. The stored
81
+ * JSON is parsed and validated against the schema before it is returned.
82
+ */
83
+ async get(key) {
84
+ const raw = await this.#namespace.get(this.name(key), "text");
85
+ return raw === null ? null : this.#parseValue(raw);
86
+ }
87
+ /** Read the value at `key` together with its validated metadata. `null` on a miss. */
88
+ async getWithMetadata(key) {
89
+ const result = await this.#namespace.getWithMetadata(this.name(key), "text");
90
+ if (result.value === null) return null;
91
+ return {
92
+ value: this.#parseValue(result.value),
93
+ metadata: this.#parseMetadata(result.metadata)
94
+ };
95
+ }
96
+ /**
97
+ * Validate `value` (and any `metadata`) against their schemas, then store the
98
+ * value as JSON under the namespaced key. With `deriveMetadata`, metadata is
99
+ * computed from the value unless overridden per call. Throws (before writing)
100
+ * on an invalid value, invalid metadata, or metadata over
101
+ * {@link KV_METADATA_MAX_BYTES}. A per-call `ttlSeconds` overrides the default.
102
+ */
103
+ async put(key, value, options = {}) {
104
+ const validated = this.#valueSchema.parse(value);
105
+ const putOptions = {};
106
+ const ttlSeconds = options.ttlSeconds ?? this.#defaultTtlSeconds;
107
+ if (ttlSeconds !== void 0) putOptions.expirationTtl = ttlSeconds;
108
+ const metadata = this.#resolveMetadata(validated, options.metadata);
109
+ if (metadata !== void 0) putOptions.metadata = metadata;
110
+ await this.#namespace.put(this.name(key), JSON.stringify(validated), putOptions);
111
+ }
112
+ /**
113
+ * Partially update the value at `key`: read it, merge `changes` over the
114
+ * current fields, validate the merged result, and write it back. Returns the
115
+ * merged value. Throws if the key does not exist — there is nothing to merge.
116
+ *
117
+ * Metadata stays correct: a `deriveMetadata` store recomputes it from the
118
+ * merged value; an explicit-metadata store preserves the current metadata
119
+ * (pass `metadata` to override). TTL resets to the store default unless
120
+ * `ttlSeconds` is given.
121
+ *
122
+ * WARNING: KV has no compare-and-set, so this read-modify-write is
123
+ * last-write-wins. Concurrent patches to the same key can lose updates — do
124
+ * not use it where atomicity matters.
125
+ */
126
+ async patch(key, changes, options = {}) {
127
+ const existing = await this.getWithMetadata(key);
128
+ if (existing === null) throw new NotFoundError({ message: `Cannot patch ${this.name(key)}: no value to update.` });
129
+ const merged = this.#valueSchema.parse({
130
+ ...existing.value,
131
+ ...changes
132
+ });
133
+ const putOptions = { ...options };
134
+ if (this.#deriveMetadata === void 0 && options.metadata === void 0 && existing.metadata !== null) putOptions.metadata = existing.metadata;
135
+ await this.put(key, merged, putOptions);
136
+ return merged;
137
+ }
138
+ /** Delete the value at `key`. A miss is a no-op. */
139
+ async delete(key) {
140
+ await this.#namespace.delete(this.name(key));
141
+ }
142
+ /**
143
+ * List entries under a leading run of key segments. Each entry carries its
144
+ * parsed key segments and validated metadata — no value reads, unless
145
+ * `deriveMetadata` is configured and an entry's metadata is missing, in which
146
+ * case it is rebuilt from the value and written back. Pass `options.prefix` to
147
+ * scope (e.g. `{ assetType: "photo" }`); omit to list the whole namespace.
148
+ */
149
+ async list(options = {}) {
150
+ const result = await this.#namespace.list({
151
+ prefix: this.#listPrefix(options.prefix),
152
+ limit: options.limit,
153
+ cursor: options.cursor
154
+ });
155
+ return {
156
+ keys: await Promise.all(result.keys.map(async (entry) => ({
157
+ name: entry.name,
158
+ key: this.#splitKey(entry.name),
159
+ metadata: await this.#resolveListMetadata(entry),
160
+ expiration: entry.expiration
161
+ }))),
162
+ cursor: result.list_complete ? void 0 : result.cursor,
163
+ listComplete: result.list_complete
164
+ };
165
+ }
166
+ /**
167
+ * Resolve one list entry's metadata: parse what is stored, else self-heal it
168
+ * from the value when `deriveMetadata` is configured. A single entry with
169
+ * corrupt or schema-incompatible metadata/value must not abort the whole
170
+ * listing — it degrades to `null` metadata while the key is still returned.
171
+ */
172
+ async #resolveListMetadata(entry) {
173
+ try {
174
+ const stored = this.#parseMetadata(entry.metadata);
175
+ if (stored !== null) return stored;
176
+ const derive = this.#deriveMetadata;
177
+ const metadataSchema = this.#metadataSchema;
178
+ if (derive === void 0 || metadataSchema === void 0) return null;
179
+ return await this.#rebuildMetadata(entry.name, entry.expiration, derive, metadataSchema);
180
+ } catch {
181
+ return null;
182
+ }
183
+ }
184
+ /** Resolve the metadata to store: explicit wins, else derive, else none. */
185
+ #resolveMetadata(value, explicit) {
186
+ if (this.#metadataSchema === void 0) return void 0;
187
+ let candidate;
188
+ if (explicit !== void 0) candidate = explicit;
189
+ else if (this.#deriveMetadata !== void 0) candidate = this.#deriveMetadata(value);
190
+ else return void 0;
191
+ return this.#validateMetadata(this.#metadataSchema, candidate);
192
+ }
193
+ /** Read the value, re-derive metadata, and write it back — preserving value bytes and expiration. */
194
+ async #rebuildMetadata(name, expiration, derive, metadataSchema) {
195
+ const raw = await this.#namespace.get(name, "text");
196
+ if (raw === null) return null;
197
+ const derived = derive(this.#parseValue(raw));
198
+ if (derived === null || derived === void 0) return null;
199
+ const metadata = this.#validateMetadata(metadataSchema, derived);
200
+ try {
201
+ const putOptions = { metadata };
202
+ if (expiration !== void 0) putOptions.expiration = expiration;
203
+ await this.#namespace.put(name, raw, putOptions);
204
+ } catch (error) {
205
+ this.#logger.warn("kv metadata heal write-back failed", {
206
+ key: name,
207
+ detail: messageOf(error)
208
+ });
209
+ }
210
+ return metadata;
211
+ }
212
+ /** Decode a stored value: JSON-parse, then validate against the value schema. */
213
+ #parseValue(raw) {
214
+ return this.#valueSchema.parse(JSON.parse(raw));
215
+ }
216
+ /** Validate a metadata candidate against the schema and the KV size cap. */
217
+ #validateMetadata(schema, candidate) {
218
+ const parsed = schema.parse(candidate);
219
+ const bytes = byteLength(JSON.stringify(parsed));
220
+ if (bytes > 1024) throw new InternalError({ message: `KV metadata is ${bytes} bytes; the limit is ${KV_METADATA_MAX_BYTES}. Keep metadata small.` });
221
+ return parsed;
222
+ }
223
+ /** Stringify and guard one key segment. */
224
+ #segment(name, value) {
225
+ const segment = String(value);
226
+ if (segment.includes(this.#separator)) throw new InternalError({
227
+ message: `Key segment "${name}" must not contain the separator "${this.#separator}".`,
228
+ detail: `Offending value for "${name}": ${segment}`
229
+ });
230
+ return segment;
231
+ }
232
+ /** Build the physical prefix string for a `list`, enforcing a proper, contiguous leading run. */
233
+ #listPrefix(parts) {
234
+ const trailing = `${this.#prefix}${this.#separator}`;
235
+ if (!parts) return trailing;
236
+ const provided = this.#keySchema.partial().parse(parts);
237
+ const present = this.#segmentNames.filter((name) => provided[name] !== void 0);
238
+ if (present.length === 0) return trailing;
239
+ if (present.length === this.#segmentNames.length) throw new InternalError({ message: "list prefix is a full key; use get() or getWithMetadata() for an exact key." });
240
+ const leading = this.#segmentNames.slice(0, present.length);
241
+ if (present.join(this.#separator) !== leading.join(this.#separator)) throw new InternalError({ message: `list prefix must be a leading run of key segments [${this.#segmentNames.join(", ")}]; got [${present.join(", ")}].` });
242
+ const segments = leading.map((name) => this.#segment(name, provided[name]));
243
+ return `${[this.#prefix, ...segments].join(this.#separator)}${this.#separator}`;
244
+ }
245
+ /** Split a physical key back into its named segments. Safe: segments never contain the separator. */
246
+ #splitKey(name) {
247
+ const segments = name.slice(this.#prefix.length + this.#separator.length).split(this.#separator);
248
+ const out = {};
249
+ this.#segmentNames.forEach((segmentName, index) => {
250
+ out[segmentName] = segments[index] ?? "";
251
+ });
252
+ return out;
253
+ }
254
+ /** Validate stored metadata against the schema; `null` when absent or unconfigured. */
255
+ #parseMetadata(raw) {
256
+ if (this.#metadataSchema === void 0 || raw === null || raw === void 0) return null;
257
+ return this.#metadataSchema.parse(raw);
258
+ }
259
+ };
260
+ //#endregion
261
+ export { KV_METADATA_MAX_BYTES, TypedKv, assertValidConfig, kvMetadata };
@@ -0,0 +1,58 @@
1
+ import type { z } from "zod";
2
+ import type { Capability } from "../capability/capability";
3
+ import { type BindingGroup } from "../capability/compose";
4
+ import type { Logger } from "../logger/logger";
5
+ import { TypedKv, type TypedKvConfig } from "./kv";
6
+ /**
7
+ * One typed store within a KV namespace — a {@link TypedKvConfig} (prefix, key, value, metadata).
8
+ * The peer of a D1 table: the binding lives on the enclosing namespace, not the store.
9
+ */
10
+ export type KvStoreSpec<V extends z.ZodType = z.ZodType, K extends z.ZodObject = z.ZodObject, M extends z.ZodType = z.ZodType> = TypedKvConfig<V, K, M>;
11
+ /** A capability's stores for one namespace: store name → {@link KvStoreSpec}. */
12
+ export type KvStoreSpecMap = Record<string, KvStoreSpec>;
13
+ /**
14
+ * One named KV namespace a capability registers — the peer of a {@link DatabaseSpec}: the `binding`
15
+ * it lives in plus the named stores it holds. `createBackend` serves each store as a live
16
+ * {@link TypedKv} on `c.var.kv.<namespace>.<store>`. Capabilities targeting the same namespace name
17
+ * merge their stores.
18
+ */
19
+ export interface KvNamespaceSpec<Stores extends KvStoreSpecMap = KvStoreSpecMap> {
20
+ /** The KV binding name in the Worker env this namespace lives in. */
21
+ binding: string;
22
+ /** The named typed stores in this namespace (store name → spec). */
23
+ stores: Stores;
24
+ }
25
+ /** A capability's KV namespaces: namespace name → {@link KvNamespaceSpec}. */
26
+ export type KvNamespaceSpecMap = Record<string, KvNamespaceSpec>;
27
+ /**
28
+ * The typed KV registry exposed on `c.var.kv`: namespace name → store name → live {@link TypedKv},
29
+ * preserving each store's value/key/metadata types — so `c.var.kv.cms.pages.get(...)` returns the
30
+ * page type, validated, and `c.var.kv.audit.pages` is a distinct store with no name conflict.
31
+ */
32
+ export type KvRegistry<Namespaces extends KvNamespaceSpecMap> = {
33
+ [Ns in keyof Namespaces]: Namespaces[Ns] extends KvNamespaceSpec<infer Stores> ? {
34
+ [S in keyof Stores]: Stores[S] extends KvStoreSpec<infer V, infer K, infer M> ? TypedKv<V, K, M> : never;
35
+ } : never;
36
+ };
37
+ /** The merged namespaces: each namespace name → its binding and the union of every capability's stores. */
38
+ export type MergedKvNamespaces = Record<string, BindingGroup<KvStoreSpec>>;
39
+ /**
40
+ * Merge every capability's `kvNamespaces` into one map keyed by namespace name. Capabilities
41
+ * targeting the same name union their stores; a store claimed twice in one namespace, or a namespace
42
+ * name bound to two bindings, throws at assembly. Mirrors `composeDatabases`.
43
+ */
44
+ export declare function composeKv(capabilities: Capability[]): MergedKvNamespaces;
45
+ /** A registry of live stores keyed by namespace then store name; the per-request value of `c.var.kv`. */
46
+ type LiveStore = TypedKv<z.ZodType, z.ZodObject, z.ZodType>;
47
+ type LiveKvRegistry = Record<string, Record<string, LiveStore>>;
48
+ /**
49
+ * Build the per-request KV registry from the merged namespaces and the request's env. Each store is
50
+ * constructed lazily on first access — a request that never touches `c.var.kv.cms.fragments` never
51
+ * builds it (mirroring Leed's lazy `KVProvider` getters) — and the namespace's binding is read from
52
+ * the per-request env at access time. `logger` is the request logger (`c.var.log`) each store routes
53
+ * its observable best-effort failures through — notably the `list` self-heal write-back; it defaults to
54
+ * the no-op logger so a store built outside a request still constructs.
55
+ */
56
+ export declare function buildKvRegistry(env: Record<string, unknown>, namespaces: MergedKvNamespaces, logger?: Logger): LiveKvRegistry;
57
+ export {};
58
+ //# sourceMappingURL=namespaces.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"namespaces.d.ts","sourceRoot":"","sources":["../../src/kv/namespaces.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,KAAK,YAAY,EAA2C,MAAM,uBAAuB,CAAC;AACnG,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,MAAM,CAAC;AAEnD;;;GAGG;AACH,MAAM,MAAM,WAAW,CACrB,CAAC,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,EAC/B,CAAC,SAAS,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,EACnC,CAAC,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,IAC7B,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AAE3B,iFAAiF;AACjF,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAEzD;;;;;GAKG;AACH,MAAM,WAAW,eAAe,CAAC,MAAM,SAAS,cAAc,GAAG,cAAc;IAC7E,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,8EAA8E;AAC9E,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAEjE;;;;GAIG;AACH,MAAM,MAAM,UAAU,CAAC,UAAU,SAAS,kBAAkB,IAAI;KAC7D,EAAE,IAAI,MAAM,UAAU,GAAG,UAAU,CAAC,EAAE,CAAC,SAAS,eAAe,CAAC,MAAM,MAAM,CAAC,GAC1E;SAAG,CAAC,IAAI,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK;KAAE,GAC5G,KAAK;CACV,CAAC;AAEF,2GAA2G;AAC3G,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC;AAE3E;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,YAAY,EAAE,UAAU,EAAE,GAAG,kBAAkB,CAOxE;AAED,yGAAyG;AACzG,KAAK,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;AAC5D,KAAK,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;AAEhE;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,UAAU,EAAE,kBAAkB,EAC9B,MAAM,GAAE,MAAmB,GAC1B,cAAc,CAiBhB"}
@@ -0,0 +1,40 @@
1
+ import { bindingGroupsFrom, composeBindingGroups } from "../capability/compose.js";
2
+ import { noopLogger } from "../logger/logger.js";
3
+ import { TypedKv } from "./kv.js";
4
+ //#region src/kv/namespaces.ts
5
+ /**
6
+ * Merge every capability's `kvNamespaces` into one map keyed by namespace name. Capabilities
7
+ * targeting the same name union their stores; a store claimed twice in one namespace, or a namespace
8
+ * name bound to two bindings, throws at assembly. Mirrors `composeDatabases`.
9
+ */
10
+ function composeKv(capabilities) {
11
+ return composeBindingGroups(capabilities, (cap) => bindingGroupsFrom(cap.kvNamespaces, (ns) => ns.stores), "KV namespace", "store");
12
+ }
13
+ /**
14
+ * Build the per-request KV registry from the merged namespaces and the request's env. Each store is
15
+ * constructed lazily on first access — a request that never touches `c.var.kv.cms.fragments` never
16
+ * builds it (mirroring Leed's lazy `KVProvider` getters) — and the namespace's binding is read from
17
+ * the per-request env at access time. `logger` is the request logger (`c.var.log`) each store routes
18
+ * its observable best-effort failures through — notably the `list` self-heal write-back; it defaults to
19
+ * the no-op logger so a store built outside a request still constructs.
20
+ */
21
+ function buildKvRegistry(env, namespaces, logger = noopLogger) {
22
+ const registry = {};
23
+ for (const [namespace, group] of Object.entries(namespaces)) {
24
+ const stores = {};
25
+ for (const [name, spec] of Object.entries(group.items)) {
26
+ let instance;
27
+ Object.defineProperty(stores, name, {
28
+ enumerable: true,
29
+ get() {
30
+ if (!instance) instance = new TypedKv(env[group.binding], spec, { logger });
31
+ return instance;
32
+ }
33
+ });
34
+ }
35
+ registry[namespace] = stores;
36
+ }
37
+ return registry;
38
+ }
39
+ //#endregion
40
+ export { buildKvRegistry, composeKv };
@@ -0,0 +1,41 @@
1
+ import { type Logger } from "./logger";
2
+ import type { LogLevel } from "./record";
3
+ /**
4
+ * Mode 1 — local diagnostics. One unified diagnostic layer for the `pithy` CLI process and a Worker
5
+ * running under `pithy dev` / `wrangler dev`. Human-readable and (optionally) colorized for a person at
6
+ * a terminal, or a `--json` structured line stream for agents and CI. This is *diagnostic logging only*
7
+ * — interactive CLI UX (prompts, spinners, `PithyError` rendering) stays on the CLI's `style.ts`.
8
+ */
9
+ /**
10
+ * Level-keyed color functions the local adapter paints with. Injected, not hard-coded: core stays free
11
+ * of ANSI, and the CLI passes its `style.ts` seam so all CLI color still flows through one place. Every
12
+ * entry is optional; a missing one renders plain.
13
+ */
14
+ export interface LocalPalette {
15
+ debug?: (text: string) => string;
16
+ info?: (text: string) => string;
17
+ warn?: (text: string) => string;
18
+ error?: (text: string) => string;
19
+ /** Dimmed secondary text — the namespace, fields, and error detail. */
20
+ dim?: (text: string) => string;
21
+ }
22
+ /** Options for {@link createLocalLogger}. */
23
+ export interface LocalLoggerOptions {
24
+ /** The threshold. Defaults to `debug` — local diagnostics are verbose by default. */
25
+ level?: LogLevel;
26
+ /** Emit each record as a `JSON.stringify` line instead of the human format — the agent/CI stream. */
27
+ json?: boolean;
28
+ /** Where a formatted line goes. Defaults to `console.error` (stderr under Node), so diagnostics never pollute a command's stdout. */
29
+ write?: (line: string) => void;
30
+ /** Optional color functions (the CLI injects its `style.ts` seam). Omitted → plain text. */
31
+ palette?: LocalPalette;
32
+ /** The clock, injectable for tests. */
33
+ now?: () => number;
34
+ }
35
+ /**
36
+ * Build a Mode 1 local logger. Same interface as every other Pithy logger; the sink either renders a
37
+ * human line (default, colorized when a palette is injected) or a `--json` structured line. Writes to
38
+ * `stderr` by default so a command's machine-readable stdout stays clean.
39
+ */
40
+ export declare function createLocalLogger(options?: LocalLoggerOptions): Logger;
41
+ //# sourceMappingURL=local.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/logger/local.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,UAAU,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAa,MAAM,UAAU,CAAC;AAGpD;;;;;GAKG;AAEH;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACjC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAChC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAChC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACjC,uEAAuE;IACvE,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CAChC;AAED,6CAA6C;AAC7C,MAAM,WAAW,kBAAkB;IACjC,qFAAqF;IACrF,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,qGAAqG;IACrG,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,qIAAqI;IACrI,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,4FAA4F;IAC5F,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,uCAAuC;IACvC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAkCD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,kBAAuB,GAAG,MAAM,CAW1E"}
@@ -0,0 +1,45 @@
1
+ import { serializeRecord } from "./record.js";
2
+ import { createLogger } from "./logger.js";
3
+ //#region src/logger/local.ts
4
+ /** Render one field value: strings verbatim, everything else as compact JSON — never throwing on a cycle/BigInt. */
5
+ function renderValue(value) {
6
+ if (typeof value === "string") return value;
7
+ try {
8
+ return JSON.stringify(value) ?? String(value);
9
+ } catch {
10
+ return String(value);
11
+ }
12
+ }
13
+ /** `key=value key=value` for the record's fields, in insertion order. */
14
+ function renderFields(fields) {
15
+ return Object.entries(fields).map(([key, value]) => `${key}=${renderValue(value)}`).join(" ");
16
+ }
17
+ /** Format one record for a terminal: `LEVEL (name) msg key=val … code detail`, colorized when a palette is set. */
18
+ function renderHuman(record, palette) {
19
+ const paint = palette?.[record.level] ?? ((text) => text);
20
+ const dim = palette?.dim ?? ((text) => text);
21
+ const parts = [paint(record.level.toUpperCase())];
22
+ if (record.name) parts.push(dim(`(${record.name})`));
23
+ parts.push(record.msg);
24
+ if (record.fields) parts.push(dim(renderFields(record.fields)));
25
+ if (record.error) {
26
+ const detail = record.error.detail ? ` ${record.error.detail}` : "";
27
+ parts.push(dim(`${record.error.code}${detail}`));
28
+ }
29
+ return parts.join(" ");
30
+ }
31
+ /**
32
+ * Build a Mode 1 local logger. Same interface as every other Pithy logger; the sink either renders a
33
+ * human line (default, colorized when a palette is injected) or a `--json` structured line. Writes to
34
+ * `stderr` by default so a command's machine-readable stdout stays clean.
35
+ */
36
+ function createLocalLogger(options = {}) {
37
+ const write = options.write ?? ((line) => console.error(line));
38
+ return createLogger({
39
+ level: options.level ?? "debug",
40
+ now: options.now,
41
+ sink: (record) => write(options.json ? serializeRecord(record) : renderHuman(record, options.palette))
42
+ });
43
+ }
44
+ //#endregion
45
+ export { createLocalLogger };
@@ -0,0 +1,56 @@
1
+ import { type LogFields, type LogLevel, type LogRecord } from "./record";
2
+ /**
3
+ * The `Logger` seam. Four levels, each taking a message plus **structured fields** (not a formatted
4
+ * string), and `child(name)` to derive a namespaced sub-logger. Shared across runtimes: the same
5
+ * interface backs the `pithy` CLI process, a Worker running locally, and a deployed Worker — only the
6
+ * adapter behind it differs. Resolve it from the request context (`c.var.log`) or the CLI process
7
+ * logger; never reach for `console`.
8
+ *
9
+ * The reserved `error` field on any call may carry a `PithyError` or `ErrorPayload` — the engine lifts
10
+ * it into the record's `error`, `detail` and all. A log is internal; this is the inverse of the HTTP
11
+ * codec, which strips `detail`. The logger must never be wired to a client-facing surface.
12
+ */
13
+ export interface Logger {
14
+ /** Dev-time diagnostics. Dropped unless the logger's level is `debug`. */
15
+ debug(msg: string, fields?: LogFields): void;
16
+ /** Normal operational events. */
17
+ info(msg: string, fields?: LogFields): void;
18
+ /** A recoverable problem worth attention. */
19
+ warn(msg: string, fields?: LogFields): void;
20
+ /** A failure that was observed. Pass `{ error }` (a PithyError) to carry its full payload. */
21
+ error(msg: string, fields?: LogFields): void;
22
+ /**
23
+ * A namespaced sub-logger. `name` composes as `parent:child`; bound `fields` merge into every record
24
+ * the child emits. Omit `name` (pass `undefined`) to bind fields only — how request-correlation
25
+ * attaches `request`/`method`/`path` without renaming the logger.
26
+ */
27
+ child(name?: string, fields?: LogFields): Logger;
28
+ }
29
+ /** A sink receives a finished {@link LogRecord}. Adapters supply one; the engine builds records and calls it. */
30
+ export type LogSink = (record: LogRecord) => void;
31
+ /** Inputs to {@link createLogger}: the level threshold, the sink, and optional bound name/fields/clock. */
32
+ export interface CreateLoggerOptions {
33
+ /** The threshold; records below it are dropped. */
34
+ level: LogLevel;
35
+ /** Where finished records go. */
36
+ sink: LogSink;
37
+ /** A starting namespace for this logger, if any. */
38
+ name?: string;
39
+ /** Fields bound onto every record this logger emits. */
40
+ fields?: LogFields;
41
+ /** The clock, injectable for tests. Defaults to `Date.now`. */
42
+ now?: () => number;
43
+ }
44
+ /**
45
+ * The shared logger engine. Both adapters build on it: they supply a {@link LogSink} and a level, and
46
+ * this handles level filtering, `child` namespacing, field merging, and error lifting — one place, so
47
+ * every adapter behaves identically.
48
+ */
49
+ export declare function createLogger(options: CreateLoggerOptions): Logger;
50
+ /**
51
+ * The safe default: a logger that drops every record. Shipped so a capability that does nothing still
52
+ * has a `c.var.log` to call, and a KV store built without a logger still logs to *somewhere*. Both
53
+ * adapters replace it; nothing has to null-check `log`.
54
+ */
55
+ export declare const noopLogger: Logger;
56
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/logger/logger.ts"],"names":[],"mappings":"AAKA,OAAO,EAAmB,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1F;;;;;;;;;;GAUG;AACH,MAAM,WAAW,MAAM;IACrB,0EAA0E;IAC1E,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC7C,iCAAiC;IACjC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5C,6CAA6C;IAC7C,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5C,8FAA8F;IAC9F,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC7C;;;;OAIG;IACH,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CAClD;AAED,iHAAiH;AACjH,MAAM,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAC;AAElD,2GAA2G;AAC3G,MAAM,WAAW,mBAAmB;IAClC,mDAAmD;IACnD,KAAK,EAAE,QAAQ,CAAC;IAChB,iCAAiC;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,+DAA+D;IAC/D,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAoED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAQjE;AAED;;;;GAIG;AACH,eAAO,MAAM,UAAU,EAAE,MAMxB,CAAC"}
@@ -0,0 +1,83 @@
1
+ import { PithyError } from "../error/pithyError.js";
2
+ import { LOG_LEVEL_ORDER } from "./record.js";
3
+ //#region src/logger/logger.ts
4
+ /**
5
+ * Duck-type an `ErrorPayload`: a **namespaced** `code` (`domain/reason`) plus an HTTP-range `status`.
6
+ * Cheap — no per-call Zod parse. The `/` and status-range checks keep an ordinary field that happens to
7
+ * be named `error` (e.g. `{ code: "retry", status: 3 }`) from being mistaken for a payload and lifted.
8
+ */
9
+ function isErrorPayloadLike(value) {
10
+ if (typeof value !== "object" || value === null) return false;
11
+ const { code, status } = value;
12
+ return typeof code === "string" && code.includes("/") && typeof status === "number" && Number.isInteger(status) && status >= 100 && status <= 599;
13
+ }
14
+ /** Build a logger over `state`: level-filters, merges bound + call fields, lifts a carried error. */
15
+ function makeLogger(state) {
16
+ const emit = (level, msg, callFields) => {
17
+ if (LOG_LEVEL_ORDER[level] < LOG_LEVEL_ORDER[state.level]) return;
18
+ const merged = {
19
+ ...state.fields,
20
+ ...callFields
21
+ };
22
+ let error;
23
+ const carried = merged.error;
24
+ if (carried instanceof PithyError) {
25
+ error = carried.payload;
26
+ delete merged.error;
27
+ } else if (isErrorPayloadLike(carried)) {
28
+ error = carried;
29
+ delete merged.error;
30
+ }
31
+ const record = {
32
+ level,
33
+ msg,
34
+ time: state.now()
35
+ };
36
+ if (state.name) record.name = state.name;
37
+ if (Object.keys(merged).length > 0) record.fields = merged;
38
+ if (error) record.error = error;
39
+ state.sink(record);
40
+ };
41
+ return {
42
+ debug: (msg, fields) => emit("debug", msg, fields),
43
+ info: (msg, fields) => emit("info", msg, fields),
44
+ warn: (msg, fields) => emit("warn", msg, fields),
45
+ error: (msg, fields) => emit("error", msg, fields),
46
+ child: (name, fields) => makeLogger({
47
+ ...state,
48
+ name: name ? state.name ? `${state.name}:${name}` : name : state.name,
49
+ fields: {
50
+ ...state.fields,
51
+ ...fields
52
+ }
53
+ })
54
+ };
55
+ }
56
+ /**
57
+ * The shared logger engine. Both adapters build on it: they supply a {@link LogSink} and a level, and
58
+ * this handles level filtering, `child` namespacing, field merging, and error lifting — one place, so
59
+ * every adapter behaves identically.
60
+ */
61
+ function createLogger(options) {
62
+ return makeLogger({
63
+ level: options.level,
64
+ sink: options.sink,
65
+ name: options.name,
66
+ fields: options.fields,
67
+ now: options.now ?? (() => Date.now())
68
+ });
69
+ }
70
+ /**
71
+ * The safe default: a logger that drops every record. Shipped so a capability that does nothing still
72
+ * has a `c.var.log` to call, and a KV store built without a logger still logs to *somewhere*. Both
73
+ * adapters replace it; nothing has to null-check `log`.
74
+ */
75
+ const noopLogger = {
76
+ debug: () => {},
77
+ info: () => {},
78
+ warn: () => {},
79
+ error: () => {},
80
+ child: () => noopLogger
81
+ };
82
+ //#endregion
83
+ export { createLogger, noopLogger };