@hs-x/cli 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 (302) hide show
  1. package/README.md +1001 -0
  2. package/dist/account-store.d.ts +51 -0
  3. package/dist/account-store.d.ts.map +1 -0
  4. package/dist/account-store.js +138 -0
  5. package/dist/account-store.js.map +1 -0
  6. package/dist/bin/hs-x.d.ts +3 -0
  7. package/dist/bin/hs-x.d.ts.map +1 -0
  8. package/dist/bin/hs-x.js +47 -0
  9. package/dist/bin/hs-x.js.map +1 -0
  10. package/dist/cli/index.d.ts +3 -0
  11. package/dist/cli/index.d.ts.map +1 -0
  12. package/dist/cli/index.js +595 -0
  13. package/dist/cli/index.js.map +1 -0
  14. package/dist/cli-error.d.ts +36 -0
  15. package/dist/cli-error.d.ts.map +1 -0
  16. package/dist/cli-error.js +40 -0
  17. package/dist/cli-error.js.map +1 -0
  18. package/dist/cloudflare-auth.d.ts +25 -0
  19. package/dist/cloudflare-auth.d.ts.map +1 -0
  20. package/dist/cloudflare-auth.js +251 -0
  21. package/dist/cloudflare-auth.js.map +1 -0
  22. package/dist/cloudflare-kv.d.ts +23 -0
  23. package/dist/cloudflare-kv.d.ts.map +1 -0
  24. package/dist/cloudflare-kv.js +101 -0
  25. package/dist/cloudflare-kv.js.map +1 -0
  26. package/dist/cloudflare-oauth-store.d.ts +16 -0
  27. package/dist/cloudflare-oauth-store.d.ts.map +1 -0
  28. package/dist/cloudflare-oauth-store.js +80 -0
  29. package/dist/cloudflare-oauth-store.js.map +1 -0
  30. package/dist/cloudflare-oauth.d.ts +82 -0
  31. package/dist/cloudflare-oauth.d.ts.map +1 -0
  32. package/dist/cloudflare-oauth.js +336 -0
  33. package/dist/cloudflare-oauth.js.map +1 -0
  34. package/dist/cloudflare-pointer.d.ts +13 -0
  35. package/dist/cloudflare-pointer.d.ts.map +1 -0
  36. package/dist/cloudflare-pointer.js +46 -0
  37. package/dist/cloudflare-pointer.js.map +1 -0
  38. package/dist/command-history.d.ts +7 -0
  39. package/dist/command-history.d.ts.map +1 -0
  40. package/dist/command-history.js +34 -0
  41. package/dist/command-history.js.map +1 -0
  42. package/dist/commands/account.d.ts +7 -0
  43. package/dist/commands/account.d.ts.map +1 -0
  44. package/dist/commands/account.js +315 -0
  45. package/dist/commands/account.js.map +1 -0
  46. package/dist/commands/api.d.ts +36 -0
  47. package/dist/commands/api.d.ts.map +1 -0
  48. package/dist/commands/api.js +521 -0
  49. package/dist/commands/api.js.map +1 -0
  50. package/dist/commands/completion.d.ts +7 -0
  51. package/dist/commands/completion.d.ts.map +1 -0
  52. package/dist/commands/completion.js +121 -0
  53. package/dist/commands/completion.js.map +1 -0
  54. package/dist/commands/connect.d.ts +7 -0
  55. package/dist/commands/connect.d.ts.map +1 -0
  56. package/dist/commands/connect.js +1123 -0
  57. package/dist/commands/connect.js.map +1 -0
  58. package/dist/commands/control-plane-read.d.ts +22 -0
  59. package/dist/commands/control-plane-read.d.ts.map +1 -0
  60. package/dist/commands/control-plane-read.js +350 -0
  61. package/dist/commands/control-plane-read.js.map +1 -0
  62. package/dist/commands/deploy-promote.d.ts +14 -0
  63. package/dist/commands/deploy-promote.d.ts.map +1 -0
  64. package/dist/commands/deploy-promote.js +105 -0
  65. package/dist/commands/deploy-promote.js.map +1 -0
  66. package/dist/commands/deploy.d.ts +18 -0
  67. package/dist/commands/deploy.d.ts.map +1 -0
  68. package/dist/commands/deploy.js +2764 -0
  69. package/dist/commands/deploy.js.map +1 -0
  70. package/dist/commands/dev.d.ts +7 -0
  71. package/dist/commands/dev.d.ts.map +1 -0
  72. package/dist/commands/dev.js +913 -0
  73. package/dist/commands/dev.js.map +1 -0
  74. package/dist/commands/doctor.d.ts +8 -0
  75. package/dist/commands/doctor.d.ts.map +1 -0
  76. package/dist/commands/doctor.js +258 -0
  77. package/dist/commands/doctor.js.map +1 -0
  78. package/dist/commands/flags.d.ts +22 -0
  79. package/dist/commands/flags.d.ts.map +1 -0
  80. package/dist/commands/flags.js +185 -0
  81. package/dist/commands/flags.js.map +1 -0
  82. package/dist/commands/help-command.d.ts +13 -0
  83. package/dist/commands/help-command.d.ts.map +1 -0
  84. package/dist/commands/help-command.js +482 -0
  85. package/dist/commands/help-command.js.map +1 -0
  86. package/dist/commands/history.d.ts +6 -0
  87. package/dist/commands/history.d.ts.map +1 -0
  88. package/dist/commands/history.js +42 -0
  89. package/dist/commands/history.js.map +1 -0
  90. package/dist/commands/init.d.ts +8 -0
  91. package/dist/commands/init.d.ts.map +1 -0
  92. package/dist/commands/init.js +233 -0
  93. package/dist/commands/init.js.map +1 -0
  94. package/dist/commands/link.d.ts +26 -0
  95. package/dist/commands/link.d.ts.map +1 -0
  96. package/dist/commands/link.js +441 -0
  97. package/dist/commands/link.js.map +1 -0
  98. package/dist/commands/login.d.ts +8 -0
  99. package/dist/commands/login.d.ts.map +1 -0
  100. package/dist/commands/login.js +381 -0
  101. package/dist/commands/login.js.map +1 -0
  102. package/dist/commands/migrate.d.ts +8 -0
  103. package/dist/commands/migrate.d.ts.map +1 -0
  104. package/dist/commands/migrate.js +258 -0
  105. package/dist/commands/migrate.js.map +1 -0
  106. package/dist/commands/rollback.d.ts +21 -0
  107. package/dist/commands/rollback.d.ts.map +1 -0
  108. package/dist/commands/rollback.js +301 -0
  109. package/dist/commands/rollback.js.map +1 -0
  110. package/dist/commands/secrets.d.ts +7 -0
  111. package/dist/commands/secrets.d.ts.map +1 -0
  112. package/dist/commands/secrets.js +230 -0
  113. package/dist/commands/secrets.js.map +1 -0
  114. package/dist/commands/status.d.ts +7 -0
  115. package/dist/commands/status.d.ts.map +1 -0
  116. package/dist/commands/status.js +241 -0
  117. package/dist/commands/status.js.map +1 -0
  118. package/dist/commands/unlink.d.ts +21 -0
  119. package/dist/commands/unlink.d.ts.map +1 -0
  120. package/dist/commands/unlink.js +83 -0
  121. package/dist/commands/unlink.js.map +1 -0
  122. package/dist/commands/update.d.ts +11 -0
  123. package/dist/commands/update.d.ts.map +1 -0
  124. package/dist/commands/update.js +154 -0
  125. package/dist/commands/update.js.map +1 -0
  126. package/dist/commands/validate.d.ts +9 -0
  127. package/dist/commands/validate.d.ts.map +1 -0
  128. package/dist/commands/validate.js +39 -0
  129. package/dist/commands/validate.js.map +1 -0
  130. package/dist/config.d.ts +12 -0
  131. package/dist/config.d.ts.map +1 -0
  132. package/dist/config.js +64 -0
  133. package/dist/config.js.map +1 -0
  134. package/dist/constants.d.ts +4 -0
  135. package/dist/constants.d.ts.map +1 -0
  136. package/dist/constants.js +4 -0
  137. package/dist/constants.js.map +1 -0
  138. package/dist/control-plane-fetch.d.ts +34 -0
  139. package/dist/control-plane-fetch.d.ts.map +1 -0
  140. package/dist/control-plane-fetch.js +73 -0
  141. package/dist/control-plane-fetch.js.map +1 -0
  142. package/dist/control-plane-loader.d.ts +16 -0
  143. package/dist/control-plane-loader.d.ts.map +1 -0
  144. package/dist/control-plane-loader.js +24 -0
  145. package/dist/control-plane-loader.js.map +1 -0
  146. package/dist/dev/compat-shim.d.ts +40 -0
  147. package/dist/dev/compat-shim.d.ts.map +1 -0
  148. package/dist/dev/compat-shim.js +65 -0
  149. package/dist/dev/compat-shim.js.map +1 -0
  150. package/dist/dev/event-bus.d.ts +27 -0
  151. package/dist/dev/event-bus.d.ts.map +1 -0
  152. package/dist/dev/event-bus.js +32 -0
  153. package/dist/dev/event-bus.js.map +1 -0
  154. package/dist/dev/log-server.d.ts +52 -0
  155. package/dist/dev/log-server.d.ts.map +1 -0
  156. package/dist/dev/log-server.js +216 -0
  157. package/dist/dev/log-server.js.map +1 -0
  158. package/dist/dev/session-manager.d.ts +33 -0
  159. package/dist/dev/session-manager.d.ts.map +1 -0
  160. package/dist/dev/session-manager.js +132 -0
  161. package/dist/dev/session-manager.js.map +1 -0
  162. package/dist/dev/stream-renderer.d.ts +22 -0
  163. package/dist/dev/stream-renderer.d.ts.map +1 -0
  164. package/dist/dev/stream-renderer.js +65 -0
  165. package/dist/dev/stream-renderer.js.map +1 -0
  166. package/dist/dev/tunnel.d.ts +40 -0
  167. package/dist/dev/tunnel.d.ts.map +1 -0
  168. package/dist/dev/tunnel.js +139 -0
  169. package/dist/dev/tunnel.js.map +1 -0
  170. package/dist/effect-http.d.ts +10 -0
  171. package/dist/effect-http.d.ts.map +1 -0
  172. package/dist/effect-http.js +38 -0
  173. package/dist/effect-http.js.map +1 -0
  174. package/dist/errors-registry.d.ts +11 -0
  175. package/dist/errors-registry.d.ts.map +1 -0
  176. package/dist/errors-registry.js +554 -0
  177. package/dist/errors-registry.js.map +1 -0
  178. package/dist/errors.d.ts +58 -0
  179. package/dist/errors.d.ts.map +1 -0
  180. package/dist/errors.js +30 -0
  181. package/dist/errors.js.map +1 -0
  182. package/dist/help.d.ts +6 -0
  183. package/dist/help.d.ts.map +1 -0
  184. package/dist/help.js +100 -0
  185. package/dist/help.js.map +1 -0
  186. package/dist/history.d.ts +15 -0
  187. package/dist/history.d.ts.map +1 -0
  188. package/dist/history.js +69 -0
  189. package/dist/history.js.map +1 -0
  190. package/dist/hubspot-auth.d.ts +53 -0
  191. package/dist/hubspot-auth.d.ts.map +1 -0
  192. package/dist/hubspot-auth.js +301 -0
  193. package/dist/hubspot-auth.js.map +1 -0
  194. package/dist/hubspot-developer-client.d.ts +10 -0
  195. package/dist/hubspot-developer-client.d.ts.map +1 -0
  196. package/dist/hubspot-developer-client.js +212 -0
  197. package/dist/hubspot-developer-client.js.map +1 -0
  198. package/dist/index.d.ts +5 -0
  199. package/dist/index.d.ts.map +1 -0
  200. package/dist/index.js +4 -0
  201. package/dist/index.js.map +1 -0
  202. package/dist/init/templates.d.ts +18 -0
  203. package/dist/init/templates.d.ts.map +1 -0
  204. package/dist/init/templates.js +239 -0
  205. package/dist/init/templates.js.map +1 -0
  206. package/dist/load-env.d.ts +16 -0
  207. package/dist/load-env.d.ts.map +1 -0
  208. package/dist/load-env.js +69 -0
  209. package/dist/load-env.js.map +1 -0
  210. package/dist/machine-id.d.ts +3 -0
  211. package/dist/machine-id.d.ts.map +1 -0
  212. package/dist/machine-id.js +41 -0
  213. package/dist/machine-id.js.map +1 -0
  214. package/dist/paths.d.ts +4 -0
  215. package/dist/paths.d.ts.map +1 -0
  216. package/dist/paths.js +19 -0
  217. package/dist/paths.js.map +1 -0
  218. package/dist/prompt.d.ts +43 -0
  219. package/dist/prompt.d.ts.map +1 -0
  220. package/dist/prompt.js +379 -0
  221. package/dist/prompt.js.map +1 -0
  222. package/dist/reporter/human.d.ts +28 -0
  223. package/dist/reporter/human.d.ts.map +1 -0
  224. package/dist/reporter/human.js +126 -0
  225. package/dist/reporter/human.js.map +1 -0
  226. package/dist/reporter/index.d.ts +14 -0
  227. package/dist/reporter/index.d.ts.map +1 -0
  228. package/dist/reporter/index.js +37 -0
  229. package/dist/reporter/index.js.map +1 -0
  230. package/dist/reporter/json.d.ts +43 -0
  231. package/dist/reporter/json.d.ts.map +1 -0
  232. package/dist/reporter/json.js +146 -0
  233. package/dist/reporter/json.js.map +1 -0
  234. package/dist/reporter/style.d.ts +34 -0
  235. package/dist/reporter/style.d.ts.map +1 -0
  236. package/dist/reporter/style.js +97 -0
  237. package/dist/reporter/style.js.map +1 -0
  238. package/dist/reporter/types.d.ts +41 -0
  239. package/dist/reporter/types.d.ts.map +1 -0
  240. package/dist/reporter/types.js +2 -0
  241. package/dist/reporter/types.js.map +1 -0
  242. package/dist/result.d.ts +4 -0
  243. package/dist/result.d.ts.map +1 -0
  244. package/dist/result.js +2 -0
  245. package/dist/result.js.map +1 -0
  246. package/dist/services/account-store.d.ts +31 -0
  247. package/dist/services/account-store.d.ts.map +1 -0
  248. package/dist/services/account-store.js +135 -0
  249. package/dist/services/account-store.js.map +1 -0
  250. package/dist/services/app-paths.d.ts +25 -0
  251. package/dist/services/app-paths.d.ts.map +1 -0
  252. package/dist/services/app-paths.js +34 -0
  253. package/dist/services/app-paths.js.map +1 -0
  254. package/dist/services/cloudflare-auth.d.ts +83 -0
  255. package/dist/services/cloudflare-auth.d.ts.map +1 -0
  256. package/dist/services/cloudflare-auth.js +30 -0
  257. package/dist/services/cloudflare-auth.js.map +1 -0
  258. package/dist/services/cloudflare-kv.d.ts +45 -0
  259. package/dist/services/cloudflare-kv.d.ts.map +1 -0
  260. package/dist/services/cloudflare-kv.js +151 -0
  261. package/dist/services/cloudflare-kv.js.map +1 -0
  262. package/dist/services/command-history.d.ts +29 -0
  263. package/dist/services/command-history.d.ts.map +1 -0
  264. package/dist/services/command-history.js +62 -0
  265. package/dist/services/command-history.js.map +1 -0
  266. package/dist/services/control-plane.d.ts +32 -0
  267. package/dist/services/control-plane.d.ts.map +1 -0
  268. package/dist/services/control-plane.js +57 -0
  269. package/dist/services/control-plane.js.map +1 -0
  270. package/dist/services/env-loader.d.ts +18 -0
  271. package/dist/services/env-loader.d.ts.map +1 -0
  272. package/dist/services/env-loader.js +34 -0
  273. package/dist/services/env-loader.js.map +1 -0
  274. package/dist/services/http.d.ts +19 -0
  275. package/dist/services/http.d.ts.map +1 -0
  276. package/dist/services/http.js +9 -0
  277. package/dist/services/http.js.map +1 -0
  278. package/dist/services/live.d.ts +16 -0
  279. package/dist/services/live.d.ts.map +1 -0
  280. package/dist/services/live.js +26 -0
  281. package/dist/services/live.js.map +1 -0
  282. package/dist/services/machine-id.d.ts +18 -0
  283. package/dist/services/machine-id.d.ts.map +1 -0
  284. package/dist/services/machine-id.js +39 -0
  285. package/dist/services/machine-id.js.map +1 -0
  286. package/dist/services/reporter.d.ts +55 -0
  287. package/dist/services/reporter.d.ts.map +1 -0
  288. package/dist/services/reporter.js +49 -0
  289. package/dist/services/reporter.js.map +1 -0
  290. package/dist/state-store.d.ts +39 -0
  291. package/dist/state-store.d.ts.map +1 -0
  292. package/dist/state-store.js +89 -0
  293. package/dist/state-store.js.map +1 -0
  294. package/dist/telemetry.d.ts +13 -0
  295. package/dist/telemetry.d.ts.map +1 -0
  296. package/dist/telemetry.js +129 -0
  297. package/dist/telemetry.js.map +1 -0
  298. package/dist/tenant-state.d.ts +69 -0
  299. package/dist/tenant-state.d.ts.map +1 -0
  300. package/dist/tenant-state.js +161 -0
  301. package/dist/tenant-state.js.map +1 -0
  302. package/package.json +38 -0
@@ -0,0 +1,31 @@
1
+ import { FileSystem, Path } from '@effect/platform';
2
+ import { Context, Effect, Layer } from 'effect';
3
+ import { type CliError } from '../cli-error.js';
4
+ import type { HsxAccountStore, HsxStoredAccount, HsxUserSession } from '../account-store.js';
5
+ import { AppPaths } from './app-paths.js';
6
+ /**
7
+ * The account store as an Effect service: bearer session + linked accounts
8
+ * persisted to `$XDG_CONFIG_HOME/hs-x/config.json` (override `HSX_STORE_PATH`).
9
+ * All I/O goes through `FileSystem`; timestamps through `Clock`. Mutations fail
10
+ * with a typed `CliError` (e.g. `HSX_E_ACCOUNT_NOT_FOUND`).
11
+ */
12
+ export interface AccountStoreApi {
13
+ /** Read the store; a missing/corrupt file yields an empty store. */
14
+ readonly load: Effect.Effect<HsxAccountStore>;
15
+ readonly isLinked: Effect.Effect<boolean>;
16
+ readonly save: (store: HsxAccountStore) => Effect.Effect<void, CliError>;
17
+ readonly setUserSession: (session: HsxUserSession) => Effect.Effect<HsxAccountStore, CliError>;
18
+ readonly clearUserSession: Effect.Effect<HsxAccountStore, CliError>;
19
+ readonly addAccount: (account: Omit<HsxStoredAccount, 'createdAt'>, options?: {
20
+ readonly makeDefault?: boolean;
21
+ }) => Effect.Effect<HsxAccountStore, CliError>;
22
+ readonly setDefault: (id: string) => Effect.Effect<HsxAccountStore, CliError>;
23
+ readonly removeAccount: (id: string) => Effect.Effect<HsxAccountStore, CliError>;
24
+ }
25
+ declare const AccountStore_base: Context.TagClass<AccountStore, "cli/AccountStore", AccountStoreApi>;
26
+ export declare class AccountStore extends AccountStore_base {
27
+ }
28
+ export declare function isActiveUserSession(session: HsxUserSession | undefined, nowMs: number): boolean;
29
+ export declare const layer: Layer.Layer<AccountStore, never, FileSystem.FileSystem | Path.Path | AppPaths>;
30
+ export {};
31
+ //# sourceMappingURL=account-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-store.d.ts","sourceRoot":"","sources":["../../src/services/account-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAS,OAAO,EAAE,MAAM,EAAE,KAAK,EAAU,MAAM,QAAQ,CAAC;AAC/D,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,cAAc,EACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,oEAAoE;IACpE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAC9C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC1C,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACzE,QAAQ,CAAC,cAAc,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;IAC/F,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;IACpE,QAAQ,CAAC,UAAU,EAAE,CACnB,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE,WAAW,CAAC,EAC5C,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAA;KAAE,KACzC,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;IAC9C,QAAQ,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;IAC9E,QAAQ,CAAC,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;CAClF;;AAED,qBAAa,YAAa,SAAQ,iBAG/B;CAAG;AA4BN,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,cAAc,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAI/F;AAED,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,KAAK,CAC7B,YAAY,EACZ,KAAK,EACL,UAAU,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,GAAG,QAAQ,CAkI7C,CAAC"}
@@ -0,0 +1,135 @@
1
+ import { FileSystem, Path } from '@effect/platform';
2
+ import { Clock, Context, Effect, Layer, Option } from 'effect';
3
+ import { cliError } from '../cli-error.js';
4
+ import { AppPaths } from './app-paths.js';
5
+ export class AccountStore extends Context.Tag('cli/AccountStore')() {
6
+ }
7
+ const EMPTY_STORE = { schemaVersion: 1, accounts: {} };
8
+ function isStoredAccount(value) {
9
+ if (!value || typeof value !== 'object')
10
+ return false;
11
+ const v = value;
12
+ return (typeof v.id === 'string' &&
13
+ typeof v.displayName === 'string' &&
14
+ typeof v.hubspotPortalId === 'number' &&
15
+ (v.source === 'connect' || v.source === 'imported') &&
16
+ typeof v.createdAt === 'string');
17
+ }
18
+ function isUserSession(value) {
19
+ if (!value || typeof value !== 'object')
20
+ return false;
21
+ const v = value;
22
+ return (typeof v.sessionToken === 'string' &&
23
+ typeof v.expiresAt === 'string' &&
24
+ typeof v.email === 'string' &&
25
+ typeof v.userId === 'string' &&
26
+ (v.accountId === undefined || typeof v.accountId === 'string'));
27
+ }
28
+ export function isActiveUserSession(session, nowMs) {
29
+ if (!session)
30
+ return false;
31
+ const expiresAt = Date.parse(session.expiresAt);
32
+ return Number.isFinite(expiresAt) && expiresAt > nowMs;
33
+ }
34
+ export const layer = Layer.effect(AccountStore, Effect.gen(function* () {
35
+ const fs = yield* FileSystem.FileSystem;
36
+ const path = yield* Path.Path;
37
+ const paths = yield* AppPaths;
38
+ const storePath = () => paths.storePath();
39
+ const load = Effect.gen(function* () {
40
+ const raw = yield* fs.readFileString(storePath()).pipe(Effect.option);
41
+ if (Option.isNone(raw))
42
+ return EMPTY_STORE;
43
+ return yield* Effect.try(() => {
44
+ const parsed = JSON.parse(raw.value);
45
+ const accounts = {};
46
+ if (parsed.accounts && typeof parsed.accounts === 'object') {
47
+ for (const [id, value] of Object.entries(parsed.accounts)) {
48
+ if (isStoredAccount(value))
49
+ accounts[id] = value;
50
+ }
51
+ }
52
+ return {
53
+ schemaVersion: 1,
54
+ ...(parsed.defaultAccountId ? { defaultAccountId: parsed.defaultAccountId } : {}),
55
+ accounts,
56
+ ...(isUserSession(parsed.userSession) ? { userSession: parsed.userSession } : {}),
57
+ };
58
+ }).pipe(Effect.orElseSucceed(() => EMPTY_STORE));
59
+ });
60
+ const save = (store) => Effect.gen(function* () {
61
+ const target = storePath();
62
+ yield* fs.makeDirectory(path.dirname(target), { recursive: true, mode: 0o700 });
63
+ yield* fs.writeFileString(target, `${JSON.stringify(store, null, 2)}\n`);
64
+ // file holds a bearer token — best-effort restrict perms (no-op on Windows)
65
+ yield* fs.chmod(target, 0o600).pipe(Effect.ignore);
66
+ }).pipe(Effect.mapError((cause) => cliError('HSX_E_INTERNAL', `Failed to write account store: ${String(cause)}`)));
67
+ const isLinked = Effect.gen(function* () {
68
+ const store = yield* load;
69
+ const nowMs = yield* Clock.currentTimeMillis;
70
+ return isActiveUserSession(store.userSession, nowMs);
71
+ });
72
+ const setUserSession = (session) => Effect.gen(function* () {
73
+ const store = yield* load;
74
+ const next = { ...store, userSession: session };
75
+ yield* save(next);
76
+ return next;
77
+ });
78
+ const clearUserSession = Effect.gen(function* () {
79
+ const store = yield* load;
80
+ const { userSession: _drop, ...rest } = store;
81
+ void _drop;
82
+ const next = rest;
83
+ yield* save(next);
84
+ return next;
85
+ });
86
+ const addAccount = (account, options = {}) => Effect.gen(function* () {
87
+ const store = yield* load;
88
+ const nowMs = yield* Clock.currentTimeMillis;
89
+ const accounts = {
90
+ ...store.accounts,
91
+ [account.id]: { ...account, createdAt: new Date(nowMs).toISOString() },
92
+ };
93
+ const defaultAccountId = options.makeDefault || !store.defaultAccountId ? account.id : store.defaultAccountId;
94
+ const next = { schemaVersion: 1, defaultAccountId, accounts };
95
+ yield* save(next);
96
+ return next;
97
+ });
98
+ const setDefault = (id) => Effect.gen(function* () {
99
+ const store = yield* load;
100
+ if (!store.accounts[id]) {
101
+ return yield* Effect.fail(cliError('HSX_E_ACCOUNT_NOT_FOUND', `No HS-X account with id ${id}.`));
102
+ }
103
+ const next = { ...store, defaultAccountId: id };
104
+ yield* save(next);
105
+ return next;
106
+ });
107
+ const removeAccount = (id) => Effect.gen(function* () {
108
+ const store = yield* load;
109
+ if (!store.accounts[id]) {
110
+ return yield* Effect.fail(cliError('HSX_E_ACCOUNT_NOT_FOUND', `No HS-X account with id ${id}.`));
111
+ }
112
+ const accounts = { ...store.accounts };
113
+ delete accounts[id];
114
+ const remaining = Object.keys(accounts);
115
+ const defaultAccountId = store.defaultAccountId === id ? remaining[0] : store.defaultAccountId;
116
+ const next = {
117
+ schemaVersion: 1,
118
+ ...(defaultAccountId ? { defaultAccountId } : {}),
119
+ accounts,
120
+ };
121
+ yield* save(next);
122
+ return next;
123
+ });
124
+ return {
125
+ load,
126
+ isLinked,
127
+ save,
128
+ setUserSession,
129
+ clearUserSession,
130
+ addAccount,
131
+ setDefault,
132
+ removeAccount,
133
+ };
134
+ }));
135
+ //# sourceMappingURL=account-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-store.js","sourceRoot":"","sources":["../../src/services/account-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { Path } from '@effect/platform';
2
+ import { Context, Layer } from 'effect';
3
+ /**
4
+ * Resolves XDG base directories for the `hs-x` app. Pure string assembly once
5
+ * the environment is captured at Layer construction — exposed as plain methods
6
+ * (no Effect) because there is no I/O, only path joining via the `Path` service.
7
+ */
8
+ export interface AppPathsApi {
9
+ readonly configPath: (file: string) => string;
10
+ readonly cachePath: (file: string) => string;
11
+ readonly statePath: (file: string) => string;
12
+ /** Account store location; honors the `HSX_STORE_PATH` override. */
13
+ readonly storePath: () => string;
14
+ }
15
+ declare const AppPaths_base: Context.TagClass<AppPaths, "cli/AppPaths", AppPathsApi>;
16
+ export declare class AppPaths extends AppPaths_base {
17
+ }
18
+ /**
19
+ * Live layer. Environment (`HOME`, `XDG_*`, `HSX_STORE_PATH`) is read through
20
+ * `Config` and `homedir()` is the single sanctioned platform fallback (the
21
+ * edge). Path joining goes through the injected `Path` service.
22
+ */
23
+ export declare const layer: Layer.Layer<AppPaths, never, Path.Path>;
24
+ export {};
25
+ //# sourceMappingURL=app-paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-paths.d.ts","sourceRoot":"","sources":["../../src/services/app-paths.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAU,OAAO,EAAU,KAAK,EAAE,MAAM,QAAQ,CAAC;AAExD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9C,QAAQ,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7C,QAAQ,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7C,oEAAoE;IACpE,QAAQ,CAAC,SAAS,EAAE,MAAM,MAAM,CAAC;CAClC;;AAED,qBAAa,QAAS,SAAQ,aAAoD;CAAG;AAIrF;;;;GAIG;AACH,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,CA0BzD,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { homedir } from 'node:os';
2
+ import { Path } from '@effect/platform';
3
+ import { Config, Context, Effect, Layer } from 'effect';
4
+ export class AppPaths extends Context.Tag('cli/AppPaths')() {
5
+ }
6
+ const APP_DIR = 'hs-x';
7
+ /**
8
+ * Live layer. Environment (`HOME`, `XDG_*`, `HSX_STORE_PATH`) is read through
9
+ * `Config` and `homedir()` is the single sanctioned platform fallback (the
10
+ * edge). Path joining goes through the injected `Path` service.
11
+ */
12
+ export const layer = Layer.effect(AppPaths, Effect.gen(function* () {
13
+ const path = yield* Path.Path;
14
+ const env = yield* Config.all({
15
+ home: Config.string('HOME').pipe(Config.withDefault('')),
16
+ xdgConfig: Config.string('XDG_CONFIG_HOME').pipe(Config.withDefault('')),
17
+ xdgCache: Config.string('XDG_CACHE_HOME').pipe(Config.withDefault('')),
18
+ xdgState: Config.string('XDG_STATE_HOME').pipe(Config.withDefault('')),
19
+ storeOverride: Config.string('HSX_STORE_PATH').pipe(Config.withDefault('')),
20
+ // every key has a default, so a config read can never actually fail here
21
+ }).pipe(Effect.orDie);
22
+ const home = env.home.length > 0 ? env.home : homedir();
23
+ const base = (override, ...segments) => override.length > 0 ? override : path.join(home, ...segments);
24
+ const configBase = base(env.xdgConfig, '.config');
25
+ const cacheBase = base(env.xdgCache, '.cache');
26
+ const stateBase = base(env.xdgState, '.local', 'state');
27
+ return {
28
+ configPath: (file) => path.join(configBase, APP_DIR, file),
29
+ cachePath: (file) => path.join(cacheBase, APP_DIR, file),
30
+ statePath: (file) => path.join(stateBase, APP_DIR, file),
31
+ storePath: () => env.storeOverride.length > 0 ? env.storeOverride : path.join(configBase, APP_DIR, 'config.json'),
32
+ };
33
+ }));
34
+ //# sourceMappingURL=app-paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-paths.js","sourceRoot":"","sources":["../../src/services/app-paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAexD,MAAM,OAAO,QAAS,SAAQ,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAyB;CAAG;AAErF,MAAM,OAAO,GAAG,MAAM,CAAC;AAEvB;;;;GAIG;AACH,MAAM,CAAC,MAAM,KAAK,GAA4C,KAAK,CAAC,MAAM,CACxE,QAAQ,EACR,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IAC9B,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;QAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACxD,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACxE,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACtE,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACtE,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAC3E,yEAAyE;KAC1E,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACtB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IACxD,MAAM,IAAI,GAAG,CAAC,QAAgB,EAAE,GAAG,QAAkB,EAAU,EAAE,CAC/D,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAC;IAChE,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACxD,OAAO;QACL,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;QAC1D,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC;QACxD,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC;QACxD,SAAS,EAAE,GAAG,EAAE,CACd,GAAG,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,aAAa,CAAC;KAC7E,CAAC;AAC1B,CAAC,CAAC,CACH,CAAC"}
@@ -0,0 +1,83 @@
1
+ import type { Schema, schemas } from '@hs-x/types';
2
+ import { Context, Effect, Layer } from 'effect';
3
+ import { type CliError } from '../cli-error.js';
4
+ import { type CloudflareTokenInfo } from '../cloudflare-auth.js';
5
+ import { type CallbackResult, type CloudflareOAuthConfig, type CloudflareOAuthTokens, type ExchangeCodeInput, type LoadCloudflareOAuthConfigInput, type PkcePair, type RefreshTokensInput } from '../cloudflare-oauth.js';
6
+ import { type CloudflareOAuthCredential, type CloudflareOAuthStore } from '../cloudflare-oauth-store.js';
7
+ type CloudflarePointer = Schema.Schema.Type<typeof schemas.CloudflarePointer>;
8
+ /** Handle returned by {@link CloudflareAuthApi.startCallbackListener}. */
9
+ export interface CallbackListenerHandle {
10
+ readonly result: Promise<CallbackResult>;
11
+ readonly close: () => Promise<void>;
12
+ }
13
+ /**
14
+ * The Cloudflare auth concern as an Effect service. Wraps the imperative
15
+ * OAuth orchestration (`cloudflare-oauth.ts` — local callback listener + browser
16
+ * handoff) and the simpler fs/http helpers (`cloudflare-auth.ts` token verify,
17
+ * `cloudflare-oauth-store.ts` refresh-token store, `cloudflare-pointer.ts`
18
+ * project pointer) behind Effect-returning methods. Failures surface as a
19
+ * typed `CliError` (`HSX_E_INTERNAL`); the underlying functions retain their
20
+ * own internal error mapping, so the wrapped boundary is uniformly `CliError`.
21
+ *
22
+ * The OAuth listener is genuinely imperative (binds a loopback HTTP server) and
23
+ * is NOT rewritten here — `startCallbackListener` returns its existing handle
24
+ * (`{ result, close }`) synchronously inside an `Effect.sync`; callers await the
25
+ * `result` Promise and invoke `close()` themselves as before.
26
+ */
27
+ export interface CloudflareAuthApi {
28
+ /** Verify an API token and introspect its granted/missing permission groups. */
29
+ readonly verifyToken: (token: string, baseUrl?: string) => Effect.Effect<CloudflareTokenInfo, CliError>;
30
+ /** Source the brokered OAuth client config (control plane, or dev env override). */
31
+ readonly loadOAuthConfig: (input?: LoadCloudflareOAuthConfigInput) => Effect.Effect<CloudflareOAuthConfig, CliError>;
32
+ /** Generate a PKCE verifier/challenge pair (S256). Pure, never fails. */
33
+ readonly generatePkce: Effect.Effect<PkcePair>;
34
+ /** Generate an opaque OAuth `state` value. Pure, never fails. */
35
+ readonly generateState: Effect.Effect<string>;
36
+ /** Build the `/oauth2/auth` URL the user's browser is sent to. */
37
+ readonly buildAuthorizeUrl: (input: {
38
+ readonly config: CloudflareOAuthConfig;
39
+ readonly pkce: PkcePair;
40
+ readonly state: string;
41
+ }) => Effect.Effect<string>;
42
+ /**
43
+ * Start the local loopback callback listener (quarantined imperative
44
+ * orchestration). Returns the existing handle synchronously; the caller
45
+ * awaits `handle.result` and calls `handle.close()`.
46
+ */
47
+ readonly startCallbackListener: (input: {
48
+ readonly port: number;
49
+ readonly expectedState: string;
50
+ readonly timeoutMs?: number;
51
+ }) => Effect.Effect<CallbackListenerHandle>;
52
+ /** Exchange an authorization code (+ PKCE verifier) for tokens. */
53
+ readonly exchangeAuthorizationCode: (input: ExchangeCodeInput) => Effect.Effect<CloudflareOAuthTokens, CliError>;
54
+ /** Refresh tokens from a stored refresh token. */
55
+ readonly refreshTokens: (input: RefreshTokensInput) => Effect.Effect<CloudflareOAuthTokens, CliError>;
56
+ /** Persist a refresh-token credential keyed by Cloudflare account id. */
57
+ readonly saveOAuthCredential: (cloudflareAccountId: string, credential: Omit<CloudflareOAuthCredential, 'updatedAt'>, options?: {
58
+ readonly path?: string;
59
+ readonly now?: () => Date;
60
+ }) => Effect.Effect<CloudflareOAuthStore, CliError>;
61
+ /** Read a stored refresh-token credential for a Cloudflare account id. */
62
+ readonly getOAuthCredential: (cloudflareAccountId: string, path?: string) => Effect.Effect<CloudflareOAuthCredential | undefined, CliError>;
63
+ /** Load the `.hs-x/cloudflare.json` pointer for a project root (or undefined). */
64
+ readonly loadPointer: (root: string) => Effect.Effect<CloudflarePointer | undefined, CliError>;
65
+ /** Create the pointer if absent, otherwise return the existing one. */
66
+ readonly ensurePointer: (input: {
67
+ readonly root: string;
68
+ readonly cloudflareAccountId: string;
69
+ readonly stateKvNamespaceId: string;
70
+ readonly stateKvNamespaceName: string;
71
+ }) => Effect.Effect<CloudflarePointer, CliError>;
72
+ /** Rewrite the pointer's `ownerId` (claim on link). */
73
+ readonly rewritePointerOwner: (input: {
74
+ readonly root: string;
75
+ readonly ownerId: string;
76
+ }) => Effect.Effect<CloudflarePointer, CliError>;
77
+ }
78
+ declare const CloudflareAuth_base: Context.TagClass<CloudflareAuth, "cli/CloudflareAuth", CloudflareAuthApi>;
79
+ export declare class CloudflareAuth extends CloudflareAuth_base {
80
+ }
81
+ export declare const layer: Layer.Layer<CloudflareAuth>;
82
+ export {};
83
+ //# sourceMappingURL=cloudflare-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-auth.d.ts","sourceRoot":"","sources":["../../src/services/cloudflare-auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { Context, Effect, Layer } from 'effect';
2
+ import { cliError } from '../cli-error.js';
3
+ import { verifyCloudflareToken } from '../cloudflare-auth.js';
4
+ import { buildAuthorizeUrl, exchangeAuthorizationCode, generatePkcePair, generateState, loadCloudflareOAuthConfig, refreshTokens, startCallbackListener, } from '../cloudflare-oauth.js';
5
+ import { getCloudflareOAuthCredential, saveCloudflareOAuthCredential, } from '../cloudflare-oauth-store.js';
6
+ import { ensureCloudflarePointer, loadCloudflarePointer, rewriteCloudflarePointerOwner, } from '../cloudflare-pointer.js';
7
+ export class CloudflareAuth extends Context.Tag('cli/CloudflareAuth')() {
8
+ }
9
+ const wrap = (thunk) => Effect.tryPromise({
10
+ try: thunk,
11
+ catch: (e) => cliError('HSX_E_INTERNAL', String(e)),
12
+ });
13
+ export const layer = Layer.succeed(CloudflareAuth, {
14
+ verifyToken: (token, baseUrl) => wrap(() => (baseUrl === undefined ? verifyCloudflareToken(token) : verifyCloudflareToken(token, baseUrl))),
15
+ loadOAuthConfig: (input) => wrap(() => loadCloudflareOAuthConfig(input)),
16
+ generatePkce: Effect.sync(() => generatePkcePair()),
17
+ generateState: Effect.sync(() => generateState()),
18
+ buildAuthorizeUrl: (input) => Effect.sync(() => buildAuthorizeUrl(input)),
19
+ startCallbackListener: (input) => Effect.sync(() => startCallbackListener(input)),
20
+ exchangeAuthorizationCode: (input) => wrap(() => exchangeAuthorizationCode(input)),
21
+ refreshTokens: (input) => wrap(() => refreshTokens(input)),
22
+ saveOAuthCredential: (cloudflareAccountId, credential, options) => wrap(() => saveCloudflareOAuthCredential(cloudflareAccountId, credential, options)),
23
+ getOAuthCredential: (cloudflareAccountId, path) => wrap(() => path === undefined
24
+ ? getCloudflareOAuthCredential(cloudflareAccountId)
25
+ : getCloudflareOAuthCredential(cloudflareAccountId, path)),
26
+ loadPointer: (root) => wrap(() => loadCloudflarePointer(root)),
27
+ ensurePointer: (input) => wrap(() => ensureCloudflarePointer(input)),
28
+ rewritePointerOwner: (input) => wrap(() => rewriteCloudflarePointerOwner(input)),
29
+ });
30
+ //# sourceMappingURL=cloudflare-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-auth.js","sourceRoot":"","sources":["../../src/services/cloudflare-auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAiB,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAA4B,MAAM,uBAAuB,CAAC;AACxF,OAAO,EACL,iBAAiB,EACjB,yBAAyB,EACzB,gBAAgB,EAChB,aAAa,EACb,yBAAyB,EACzB,aAAa,EACb,qBAAqB,GAQtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,4BAA4B,EAC5B,6BAA6B,GAG9B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,6BAA6B,GAC9B,MAAM,0BAA0B,CAAC;AAkGlC,MAAM,OAAO,cAAe,SAAQ,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAGlE;CAAG;AAEN,MAAM,IAAI,GAAG,CAAI,KAAuB,EAA8B,EAAE,CACtE,MAAM,CAAC,UAAU,CAAC;IAChB,GAAG,EAAE,KAAK;IACV,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;CACpD,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,KAAK,GAAgC,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE;IAC9E,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAC9B,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;IAE5G,eAAe,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,yBAAyB,CAAC,KAAK,CAAC,CAAC;IAExE,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,gBAAgB,EAAE,CAAC;IAEnD,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC;IAEjD,iBAAiB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;IAEzE,qBAAqB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAEjF,yBAAyB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,yBAAyB,CAAC,KAAK,CAAC,CAAC;IAElF,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAE1D,mBAAmB,EAAE,CAAC,mBAAmB,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,CAChE,IAAI,CAAC,GAAG,EAAE,CAAC,6BAA6B,CAAC,mBAAmB,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;IAErF,kBAAkB,EAAE,CAAC,mBAAmB,EAAE,IAAI,EAAE,EAAE,CAChD,IAAI,CAAC,GAAG,EAAE,CACR,IAAI,KAAK,SAAS;QAChB,CAAC,CAAC,4BAA4B,CAAC,mBAAmB,CAAC;QACnD,CAAC,CAAC,4BAA4B,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAC5D;IAEH,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAE9D,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC;IAEpE,mBAAmB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,6BAA6B,CAAC,KAAK,CAAC,CAAC;CACrD,CAAC,CAAC"}
@@ -0,0 +1,45 @@
1
+ import { Context, Effect, Layer } from 'effect';
2
+ import { type CliError } from '../cli-error.js';
3
+ import { CliHttp } from './http.js';
4
+ export interface CloudflareKvNamespace {
5
+ readonly id: string;
6
+ readonly title: string;
7
+ }
8
+ /**
9
+ * A credential- and namespace-bound Cloudflare KV client. All methods return
10
+ * Effects that fail with a typed `CliError` (`HSX_E_API_NETWORK` for transport
11
+ * / HTTP failures, `HSX_E_INTERNAL` for invariant violations). The active
12
+ * namespace id is held in a `Ref` so `ensureNamespace` can latch it for later
13
+ * value/key operations within the same handle.
14
+ */
15
+ export interface CloudflareKvHandle {
16
+ readonly ensureNamespace: (name: string) => Effect.Effect<CloudflareKvNamespace, CliError>;
17
+ readonly get: (key: string) => Effect.Effect<string | undefined, CliError>;
18
+ readonly put: (key: string, value: string) => Effect.Effect<void, CliError>;
19
+ readonly list: (prefix: string) => Effect.Effect<readonly string[], CliError>;
20
+ readonly delete: (key: string) => Effect.Effect<void, CliError>;
21
+ }
22
+ /**
23
+ * Cloudflare KV access as an injectable service. `make` builds a handle bound
24
+ * to a set of credentials + (optional) namespace; `resolveCredentials` merges
25
+ * argv-flag overrides over the environment (read via `Config` at layer build).
26
+ * Depends on `CliHttp` for all transport — never touches raw `fetch`.
27
+ */
28
+ export interface CloudflareKvApi {
29
+ readonly make: (input: {
30
+ readonly accountId: string;
31
+ readonly apiToken: string;
32
+ readonly namespaceId?: string;
33
+ readonly baseUrl?: string;
34
+ }) => Effect.Effect<CloudflareKvHandle>;
35
+ readonly resolveCredentials: (argv: readonly string[]) => Effect.Effect<{
36
+ readonly apiToken: string | undefined;
37
+ readonly accountId: string | undefined;
38
+ }>;
39
+ }
40
+ declare const CloudflareKv_base: Context.TagClass<CloudflareKv, "cli/CloudflareKv", CloudflareKvApi>;
41
+ export declare class CloudflareKv extends CloudflareKv_base {
42
+ }
43
+ export declare const layer: Layer.Layer<CloudflareKv, never, CliHttp>;
44
+ export {};
45
+ //# sourceMappingURL=cloudflare-kv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-kv.d.ts","sourceRoot":"","sources":["../../src/services/cloudflare-kv.ts"],"names":[],"mappings":"AACA,OAAO,EAAU,OAAO,EAAE,MAAM,EAAE,KAAK,EAAO,MAAM,QAAQ,CAAC;AAC7D,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,qBAAqB,EAAE,QAAQ,CAAC,CAAC;IAC3F,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC3E,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC5E,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,SAAS,MAAM,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC9E,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;CACjE;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE;QACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;KAC3B,KAAK,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;IACxC,QAAQ,CAAC,kBAAkB,EAAE,CAC3B,IAAI,EAAE,SAAS,MAAM,EAAE,KACpB,MAAM,CAAC,MAAM,CAAC;QAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC,CAAC;CACvG;;AAED,qBAAa,YAAa,SAAQ,iBAG/B;CAAG;AAEN,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,EAAE,OAAO,CAuN3D,CAAC"}
@@ -0,0 +1,151 @@
1
+ import { HttpClientRequest } from '@hs-x/types';
2
+ import { Config, Context, Effect, Layer, Ref } from 'effect';
3
+ import { cliError } from '../cli-error.js';
4
+ import { CliHttp } from './http.js';
5
+ const DEFAULT_BASE_URL = 'https://api.cloudflare.com';
6
+ export class CloudflareKv extends Context.Tag('cli/CloudflareKv')() {
7
+ }
8
+ export const layer = Layer.effect(CloudflareKv, Effect.gen(function* () {
9
+ const http = yield* CliHttp;
10
+ // Environment fallbacks for credentials, read once at layer construction.
11
+ const env = yield* Config.all({
12
+ envApiTokenHsx: Config.string('HSX_CLOUDFLARE_API_TOKEN').pipe(Config.withDefault('')),
13
+ envApiToken: Config.string('CLOUDFLARE_API_TOKEN').pipe(Config.withDefault('')),
14
+ envAccountIdHsx: Config.string('HSX_CLOUDFLARE_ACCOUNT_ID').pipe(Config.withDefault('')),
15
+ envAccountId: Config.string('CLOUDFLARE_ACCOUNT_ID').pipe(Config.withDefault('')),
16
+ // every key has a default, so a config read can never actually fail here
17
+ }).pipe(Effect.orDie);
18
+ const make = (input) => Effect.gen(function* () {
19
+ const baseUrl = input.baseUrl ?? DEFAULT_BASE_URL;
20
+ const namespaceRef = yield* Ref.make(input.namespaceId);
21
+ const buildUrl = (path) => new URL(path, baseUrl);
22
+ const baseHeaders = (extra) => ({
23
+ authorization: `Bearer ${input.apiToken}`,
24
+ ...(extra ?? {}),
25
+ });
26
+ // GET-style request that fails on any non-ok status.
27
+ const execOk = (path) => Effect.gen(function* () {
28
+ const request = HttpClientRequest.make('GET')(buildUrl(path)).pipe(HttpClientRequest.setHeaders(baseHeaders()));
29
+ const response = yield* http.execute(request);
30
+ if (!response.ok) {
31
+ const detail = yield* readTextSafe(response);
32
+ return yield* Effect.fail(cliError('HSX_E_API_NETWORK', `Cloudflare KV request failed (${response.status})${detail ? `: ${detail}` : ''}`));
33
+ }
34
+ return response;
35
+ });
36
+ const requireNamespaceId = () => Effect.flatMap(Ref.get(namespaceRef), (id) => id
37
+ ? Effect.succeed(id)
38
+ : Effect.fail(cliError('HSX_E_INTERNAL', 'Cloudflare KV namespace has not been initialized.')));
39
+ const namespacesPath = `/client/v4/accounts/${encodeURIComponent(input.accountId)}/storage/kv/namespaces`;
40
+ const ensureNamespace = (name) => Effect.gen(function* () {
41
+ const listResponse = yield* execOk(namespacesPath);
42
+ const listBody = yield* readJson(listResponse);
43
+ const existing = listBody.result?.find((item) => item.title === name);
44
+ if (existing?.id && existing.title) {
45
+ yield* Ref.set(namespaceRef, existing.id);
46
+ return { id: existing.id, title: existing.title };
47
+ }
48
+ const createRequest = HttpClientRequest.make('POST')(buildUrl(namespacesPath)).pipe(HttpClientRequest.setHeaders(baseHeaders()), HttpClientRequest.bodyText(JSON.stringify({ title: name }), 'application/json'));
49
+ const createResponse = yield* http.execute(createRequest);
50
+ if (!createResponse.ok) {
51
+ const detail = yield* readTextSafe(createResponse);
52
+ return yield* Effect.fail(cliError('HSX_E_API_NETWORK', `Cloudflare KV request failed (${createResponse.status})${detail ? `: ${detail}` : ''}`));
53
+ }
54
+ const createBody = yield* readJson(createResponse);
55
+ if (!createBody.result?.id) {
56
+ return yield* Effect.fail(cliError('HSX_E_INTERNAL', 'Cloudflare KV namespace create response did not include an id.'));
57
+ }
58
+ yield* Ref.set(namespaceRef, createBody.result.id);
59
+ return { id: createBody.result.id, title: createBody.result.title ?? name };
60
+ });
61
+ const valuePath = (namespaceId, key) => `/client/v4/accounts/${encodeURIComponent(input.accountId)}/storage/kv/namespaces/${encodeURIComponent(namespaceId)}/values/${encodeURIComponent(key)}`;
62
+ const get = (key) => Effect.gen(function* () {
63
+ const namespaceId = yield* requireNamespaceId();
64
+ const request = HttpClientRequest.make('GET')(buildUrl(valuePath(namespaceId, key))).pipe(HttpClientRequest.setHeaders(baseHeaders()));
65
+ const response = yield* http.execute(request);
66
+ if (response.status === 404)
67
+ return undefined;
68
+ if (!response.ok) {
69
+ return yield* Effect.fail(cliError('HSX_E_API_NETWORK', `Cloudflare KV get failed (${response.status}).`));
70
+ }
71
+ return yield* readText(response);
72
+ });
73
+ const put = (key, value) => Effect.gen(function* () {
74
+ const namespaceId = yield* requireNamespaceId();
75
+ const request = HttpClientRequest.make('PUT')(buildUrl(valuePath(namespaceId, key))).pipe(HttpClientRequest.setHeaders(baseHeaders()), HttpClientRequest.bodyText(value, 'text/plain'));
76
+ const response = yield* http.execute(request);
77
+ if (!response.ok) {
78
+ const detail = yield* readTextSafe(response);
79
+ return yield* Effect.fail(cliError('HSX_E_API_NETWORK', `Cloudflare KV request failed (${response.status})${detail ? `: ${detail}` : ''}`));
80
+ }
81
+ });
82
+ const list = (prefix) => Effect.gen(function* () {
83
+ const namespaceId = yield* requireNamespaceId();
84
+ const keysPath = `/client/v4/accounts/${encodeURIComponent(input.accountId)}/storage/kv/namespaces/${encodeURIComponent(namespaceId)}/keys`;
85
+ const keys = [];
86
+ let cursor;
87
+ do {
88
+ const url = buildUrl(keysPath);
89
+ url.searchParams.set('prefix', prefix);
90
+ if (cursor)
91
+ url.searchParams.set('cursor', cursor);
92
+ const response = yield* execOk(`${url.pathname}${url.search}`);
93
+ const body = yield* readJson(response);
94
+ keys.push(...(body.result ?? []).flatMap((item) => (item.name ? [item.name] : [])));
95
+ cursor = body.result_info?.cursor || undefined;
96
+ } while (cursor);
97
+ return keys;
98
+ });
99
+ const del = (key) => Effect.gen(function* () {
100
+ const namespaceId = yield* requireNamespaceId();
101
+ const request = HttpClientRequest.make('DELETE')(buildUrl(valuePath(namespaceId, key))).pipe(HttpClientRequest.setHeaders(baseHeaders()));
102
+ const response = yield* http.execute(request);
103
+ if (!response.ok) {
104
+ const detail = yield* readTextSafe(response);
105
+ return yield* Effect.fail(cliError('HSX_E_API_NETWORK', `Cloudflare KV request failed (${response.status})${detail ? `: ${detail}` : ''}`));
106
+ }
107
+ });
108
+ return {
109
+ ensureNamespace,
110
+ get,
111
+ put,
112
+ list,
113
+ delete: del,
114
+ };
115
+ });
116
+ const resolveCredentials = (argv) => Effect.sync(() => {
117
+ const envApiToken = env.envApiTokenHsx || env.envApiToken || undefined;
118
+ const envAccountId = env.envAccountIdHsx || env.envAccountId || undefined;
119
+ return {
120
+ apiToken: resolveFlag(argv, '--cloudflare-api-token') ??
121
+ resolveFlag(argv, '--api-token') ??
122
+ envApiToken,
123
+ accountId: resolveFlag(argv, '--cloudflare-account-id') ?? envAccountId,
124
+ };
125
+ });
126
+ return { make, resolveCredentials };
127
+ }));
128
+ function readJson(response) {
129
+ return Effect.tryPromise({
130
+ try: () => response.json(),
131
+ catch: (cause) => cliError('HSX_E_API_NETWORK', `Failed to parse Cloudflare KV response: ${String(cause)}`),
132
+ });
133
+ }
134
+ function readText(response) {
135
+ return Effect.tryPromise({
136
+ try: () => response.text(),
137
+ catch: (cause) => cliError('HSX_E_API_NETWORK', `Failed to read Cloudflare KV response: ${String(cause)}`),
138
+ });
139
+ }
140
+ /** Best-effort body text for error detail; never fails the surrounding Effect. */
141
+ function readTextSafe(response) {
142
+ return Effect.promise(() => response.text().catch(() => ''));
143
+ }
144
+ function resolveFlag(argv, name) {
145
+ const eq = argv.find((arg) => arg.startsWith(`${name}=`));
146
+ if (eq)
147
+ return eq.slice(name.length + 1);
148
+ const idx = argv.indexOf(name);
149
+ return idx >= 0 ? argv[idx + 1] : undefined;
150
+ }
151
+ //# sourceMappingURL=cloudflare-kv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-kv.js","sourceRoot":"","sources":["../../src/services/cloudflare-kv.ts"],"names":[],"mappings":"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"}