@hs-x/cli 0.2.6 → 0.3.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 (298) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +25 -8
  3. package/dist/audit-interactive.d.ts +29 -0
  4. package/dist/audit-interactive.d.ts.map +1 -0
  5. package/dist/audit-interactive.js +156 -0
  6. package/dist/audit-interactive.js.map +1 -0
  7. package/dist/bin/hs-x.js.map +1 -1
  8. package/dist/checkpoint-interactive.d.ts +24 -0
  9. package/dist/checkpoint-interactive.d.ts.map +1 -0
  10. package/dist/checkpoint-interactive.js +65 -0
  11. package/dist/checkpoint-interactive.js.map +1 -0
  12. package/dist/cli/index.d.ts.map +1 -1
  13. package/dist/cli/index.js +266 -39
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/cli/kit.d.ts +1 -1
  16. package/dist/cli/kit.d.ts.map +1 -1
  17. package/dist/cli/kit.js +19 -3
  18. package/dist/cli/kit.js.map +1 -1
  19. package/dist/cloudflare-auth.d.ts +8 -0
  20. package/dist/cloudflare-auth.d.ts.map +1 -1
  21. package/dist/cloudflare-auth.js +12 -2
  22. package/dist/cloudflare-auth.js.map +1 -1
  23. package/dist/cloudflare-oauth-store.d.ts +9 -1
  24. package/dist/cloudflare-oauth-store.d.ts.map +1 -1
  25. package/dist/cloudflare-oauth-store.js +23 -4
  26. package/dist/cloudflare-oauth-store.js.map +1 -1
  27. package/dist/cloudflare-oauth.d.ts +1 -0
  28. package/dist/cloudflare-oauth.d.ts.map +1 -1
  29. package/dist/cloudflare-oauth.js +6 -2
  30. package/dist/cloudflare-oauth.js.map +1 -1
  31. package/dist/cloudflare-worker-versions.d.ts +184 -0
  32. package/dist/cloudflare-worker-versions.d.ts.map +1 -0
  33. package/dist/cloudflare-worker-versions.js +360 -0
  34. package/dist/cloudflare-worker-versions.js.map +1 -0
  35. package/dist/commands/account.d.ts +28 -13
  36. package/dist/commands/account.d.ts.map +1 -1
  37. package/dist/commands/account.js +219 -69
  38. package/dist/commands/account.js.map +1 -1
  39. package/dist/commands/api.d.ts +1 -1
  40. package/dist/commands/api.d.ts.map +1 -1
  41. package/dist/commands/api.js +6 -10
  42. package/dist/commands/api.js.map +1 -1
  43. package/dist/commands/completion.d.ts.map +1 -1
  44. package/dist/commands/completion.js +13 -7
  45. package/dist/commands/completion.js.map +1 -1
  46. package/dist/commands/connect.d.ts.map +1 -1
  47. package/dist/commands/connect.js +239 -125
  48. package/dist/commands/connect.js.map +1 -1
  49. package/dist/commands/control-plane-read.d.ts +72 -11
  50. package/dist/commands/control-plane-read.d.ts.map +1 -1
  51. package/dist/commands/control-plane-read.js +1035 -58
  52. package/dist/commands/control-plane-read.js.map +1 -1
  53. package/dist/commands/deploy-promote.d.ts +25 -3
  54. package/dist/commands/deploy-promote.d.ts.map +1 -1
  55. package/dist/commands/deploy-promote.js +314 -38
  56. package/dist/commands/deploy-promote.js.map +1 -1
  57. package/dist/commands/deploy.d.ts +67 -4
  58. package/dist/commands/deploy.d.ts.map +1 -1
  59. package/dist/commands/deploy.js +1333 -255
  60. package/dist/commands/deploy.js.map +1 -1
  61. package/dist/commands/dev.d.ts +5 -1
  62. package/dist/commands/dev.d.ts.map +1 -1
  63. package/dist/commands/dev.js +502 -107
  64. package/dist/commands/dev.js.map +1 -1
  65. package/dist/commands/doctor.d.ts +15 -1
  66. package/dist/commands/doctor.d.ts.map +1 -1
  67. package/dist/commands/doctor.js +131 -20
  68. package/dist/commands/doctor.js.map +1 -1
  69. package/dist/commands/flags.d.ts +108 -6
  70. package/dist/commands/flags.d.ts.map +1 -1
  71. package/dist/commands/flags.js +996 -75
  72. package/dist/commands/flags.js.map +1 -1
  73. package/dist/commands/help-command.d.ts +14 -0
  74. package/dist/commands/help-command.d.ts.map +1 -1
  75. package/dist/commands/help-command.js +144 -44
  76. package/dist/commands/help-command.js.map +1 -1
  77. package/dist/commands/history.js +14 -10
  78. package/dist/commands/history.js.map +1 -1
  79. package/dist/commands/init.d.ts +4 -2
  80. package/dist/commands/init.d.ts.map +1 -1
  81. package/dist/commands/init.js +69 -12
  82. package/dist/commands/init.js.map +1 -1
  83. package/dist/commands/link.d.ts +2 -3
  84. package/dist/commands/link.d.ts.map +1 -1
  85. package/dist/commands/link.js +201 -101
  86. package/dist/commands/link.js.map +1 -1
  87. package/dist/commands/login.d.ts +2 -2
  88. package/dist/commands/login.d.ts.map +1 -1
  89. package/dist/commands/login.js +22 -5
  90. package/dist/commands/login.js.map +1 -1
  91. package/dist/commands/migrate.d.ts +23 -3
  92. package/dist/commands/migrate.d.ts.map +1 -1
  93. package/dist/commands/migrate.js +500 -73
  94. package/dist/commands/migrate.js.map +1 -1
  95. package/dist/commands/rollback.d.ts +42 -2
  96. package/dist/commands/rollback.d.ts.map +1 -1
  97. package/dist/commands/rollback.js +422 -58
  98. package/dist/commands/rollback.js.map +1 -1
  99. package/dist/commands/secrets.d.ts +76 -3
  100. package/dist/commands/secrets.d.ts.map +1 -1
  101. package/dist/commands/secrets.js +328 -41
  102. package/dist/commands/secrets.js.map +1 -1
  103. package/dist/commands/status.d.ts +13 -2
  104. package/dist/commands/status.d.ts.map +1 -1
  105. package/dist/commands/status.js +154 -17
  106. package/dist/commands/status.js.map +1 -1
  107. package/dist/commands/unlink.d.ts +2 -2
  108. package/dist/commands/unlink.d.ts.map +1 -1
  109. package/dist/commands/unlink.js +2 -2
  110. package/dist/commands/unlink.js.map +1 -1
  111. package/dist/commands/update.d.ts.map +1 -1
  112. package/dist/commands/update.js +4 -3
  113. package/dist/commands/update.js.map +1 -1
  114. package/dist/commands/validate.d.ts +12 -3
  115. package/dist/commands/validate.d.ts.map +1 -1
  116. package/dist/commands/validate.js +70 -8
  117. package/dist/commands/validate.js.map +1 -1
  118. package/dist/constants.d.ts +1 -1
  119. package/dist/constants.js +1 -1
  120. package/dist/control-plane-fetch.d.ts.map +1 -1
  121. package/dist/control-plane-fetch.js +5 -4
  122. package/dist/control-plane-fetch.js.map +1 -1
  123. package/dist/deploy-revision-capture.d.ts +48 -0
  124. package/dist/deploy-revision-capture.d.ts.map +1 -0
  125. package/dist/deploy-revision-capture.js +125 -0
  126. package/dist/deploy-revision-capture.js.map +1 -0
  127. package/dist/dev/compat-shim.d.ts.map +1 -1
  128. package/dist/dev/compat-shim.js +10 -35
  129. package/dist/dev/compat-shim.js.map +1 -1
  130. package/dist/dev/event-bus.d.ts +5 -2
  131. package/dist/dev/event-bus.d.ts.map +1 -1
  132. package/dist/dev/event-bus.js +4 -1
  133. package/dist/dev/event-bus.js.map +1 -1
  134. package/dist/dev/hubspot-logs-poller.d.ts +35 -0
  135. package/dist/dev/hubspot-logs-poller.d.ts.map +1 -0
  136. package/dist/dev/hubspot-logs-poller.js +94 -0
  137. package/dist/dev/hubspot-logs-poller.js.map +1 -0
  138. package/dist/dev/invoke.d.ts +9 -1
  139. package/dist/dev/invoke.d.ts.map +1 -1
  140. package/dist/dev/invoke.js +69 -20
  141. package/dist/dev/invoke.js.map +1 -1
  142. package/dist/dev/keyboard.d.ts +31 -0
  143. package/dist/dev/keyboard.d.ts.map +1 -0
  144. package/dist/dev/keyboard.js +143 -0
  145. package/dist/dev/keyboard.js.map +1 -0
  146. package/dist/dev/log-server.d.ts +7 -0
  147. package/dist/dev/log-server.d.ts.map +1 -1
  148. package/dist/dev/log-server.js +68 -31
  149. package/dist/dev/log-server.js.map +1 -1
  150. package/dist/dev/migrated-card.d.ts +17 -0
  151. package/dist/dev/migrated-card.d.ts.map +1 -0
  152. package/dist/dev/migrated-card.js +114 -0
  153. package/dist/dev/migrated-card.js.map +1 -0
  154. package/dist/dev/stream-filter.d.ts +40 -0
  155. package/dist/dev/stream-filter.d.ts.map +1 -0
  156. package/dist/dev/stream-filter.js +93 -0
  157. package/dist/dev/stream-filter.js.map +1 -0
  158. package/dist/dev/stream-renderer.d.ts +34 -0
  159. package/dist/dev/stream-renderer.d.ts.map +1 -1
  160. package/dist/dev/stream-renderer.js +222 -8
  161. package/dist/dev/stream-renderer.js.map +1 -1
  162. package/dist/errors-registry.d.ts.map +1 -1
  163. package/dist/errors-registry.js +280 -36
  164. package/dist/errors-registry.js.map +1 -1
  165. package/dist/errors.d.ts.map +1 -1
  166. package/dist/errors.js.map +1 -1
  167. package/dist/help.d.ts.map +1 -1
  168. package/dist/help.js +8 -0
  169. package/dist/help.js.map +1 -1
  170. package/dist/hubspot-app-logs.d.ts +76 -0
  171. package/dist/hubspot-app-logs.d.ts.map +1 -0
  172. package/dist/hubspot-app-logs.js +323 -0
  173. package/dist/hubspot-app-logs.js.map +1 -0
  174. package/dist/hubspot-auth.d.ts +8 -2
  175. package/dist/hubspot-auth.d.ts.map +1 -1
  176. package/dist/hubspot-auth.js +36 -12
  177. package/dist/hubspot-auth.js.map +1 -1
  178. package/dist/hubspot-developer-client.js +119 -11
  179. package/dist/hubspot-developer-client.js.map +1 -1
  180. package/dist/index.d.ts +1 -0
  181. package/dist/index.d.ts.map +1 -1
  182. package/dist/index.js +1 -0
  183. package/dist/index.js.map +1 -1
  184. package/dist/init/templates.d.ts +10 -0
  185. package/dist/init/templates.d.ts.map +1 -1
  186. package/dist/init/templates.js +157 -14
  187. package/dist/init/templates.js.map +1 -1
  188. package/dist/link-migration-journal.d.ts +131 -0
  189. package/dist/link-migration-journal.d.ts.map +1 -0
  190. package/dist/link-migration-journal.js +395 -0
  191. package/dist/link-migration-journal.js.map +1 -0
  192. package/dist/link-preflight.d.ts +78 -0
  193. package/dist/link-preflight.d.ts.map +1 -0
  194. package/dist/link-preflight.js +231 -0
  195. package/dist/link-preflight.js.map +1 -0
  196. package/dist/local-project-picker.d.ts +34 -0
  197. package/dist/local-project-picker.d.ts.map +1 -0
  198. package/dist/local-project-picker.js +121 -0
  199. package/dist/local-project-picker.js.map +1 -0
  200. package/dist/logs-interactive.d.ts +37 -0
  201. package/dist/logs-interactive.d.ts.map +1 -0
  202. package/dist/logs-interactive.js +110 -0
  203. package/dist/logs-interactive.js.map +1 -0
  204. package/dist/output-context.d.ts +13 -0
  205. package/dist/output-context.d.ts.map +1 -0
  206. package/dist/output-context.js +46 -0
  207. package/dist/output-context.js.map +1 -0
  208. package/dist/project-context.d.ts +55 -0
  209. package/dist/project-context.d.ts.map +1 -0
  210. package/dist/project-context.js +115 -0
  211. package/dist/project-context.js.map +1 -0
  212. package/dist/project-picker.d.ts +65 -0
  213. package/dist/project-picker.d.ts.map +1 -0
  214. package/dist/project-picker.js +227 -0
  215. package/dist/project-picker.js.map +1 -0
  216. package/dist/prompt.d.ts +8 -0
  217. package/dist/prompt.d.ts.map +1 -1
  218. package/dist/prompt.js +81 -13
  219. package/dist/prompt.js.map +1 -1
  220. package/dist/reporter/human.d.ts +10 -2
  221. package/dist/reporter/human.d.ts.map +1 -1
  222. package/dist/reporter/human.js +82 -14
  223. package/dist/reporter/human.js.map +1 -1
  224. package/dist/reporter/index.d.ts.map +1 -1
  225. package/dist/reporter/index.js +7 -5
  226. package/dist/reporter/index.js.map +1 -1
  227. package/dist/reporter/json.d.ts +2 -1
  228. package/dist/reporter/json.d.ts.map +1 -1
  229. package/dist/reporter/json.js +10 -7
  230. package/dist/reporter/json.js.map +1 -1
  231. package/dist/reporter/style.d.ts +19 -0
  232. package/dist/reporter/style.d.ts.map +1 -1
  233. package/dist/reporter/style.js +126 -6
  234. package/dist/reporter/style.js.map +1 -1
  235. package/dist/reporter/types.d.ts +34 -4
  236. package/dist/reporter/types.d.ts.map +1 -1
  237. package/dist/reporter/types.js.map +1 -1
  238. package/dist/rollback-traffic.d.ts +85 -0
  239. package/dist/rollback-traffic.d.ts.map +1 -0
  240. package/dist/rollback-traffic.js +204 -0
  241. package/dist/rollback-traffic.js.map +1 -0
  242. package/dist/services/account-store.d.ts +3 -1
  243. package/dist/services/account-store.d.ts.map +1 -1
  244. package/dist/services/account-store.js +2 -1
  245. package/dist/services/account-store.js.map +1 -1
  246. package/dist/services/app-paths.d.ts.map +1 -1
  247. package/dist/services/app-paths.js +3 -1
  248. package/dist/services/app-paths.js.map +1 -1
  249. package/dist/services/cloudflare-auth.d.ts +1 -1
  250. package/dist/services/cloudflare-auth.d.ts.map +1 -1
  251. package/dist/services/cloudflare-auth.js +2 -2
  252. package/dist/services/cloudflare-auth.js.map +1 -1
  253. package/dist/services/cloudflare-kv.d.ts.map +1 -1
  254. package/dist/services/cloudflare-kv.js.map +1 -1
  255. package/dist/services/command-history.d.ts.map +1 -1
  256. package/dist/services/command-history.js.map +1 -1
  257. package/dist/services/config.d.ts.map +1 -1
  258. package/dist/services/config.js +1 -1
  259. package/dist/services/config.js.map +1 -1
  260. package/dist/services/control-plane.d.ts.map +1 -1
  261. package/dist/services/control-plane.js +3 -3
  262. package/dist/services/control-plane.js.map +1 -1
  263. package/dist/services/env-loader.d.ts.map +1 -1
  264. package/dist/services/env-loader.js +1 -3
  265. package/dist/services/env-loader.js.map +1 -1
  266. package/dist/services/http.d.ts.map +1 -1
  267. package/dist/services/http.js.map +1 -1
  268. package/dist/services/hubspot-dev-client.d.ts.map +1 -1
  269. package/dist/services/hubspot-dev-client.js +30 -0
  270. package/dist/services/hubspot-dev-client.js.map +1 -1
  271. package/dist/services/live.d.ts +2 -2
  272. package/dist/services/live.d.ts.map +1 -1
  273. package/dist/services/live.js +1 -1
  274. package/dist/services/live.js.map +1 -1
  275. package/dist/services/machine-id.d.ts.map +1 -1
  276. package/dist/services/machine-id.js.map +1 -1
  277. package/dist/services/reporter.d.ts +8 -5
  278. package/dist/services/reporter.d.ts.map +1 -1
  279. package/dist/services/reporter.js +6 -4
  280. package/dist/services/reporter.js.map +1 -1
  281. package/dist/services/tenant-state.d.ts.map +1 -1
  282. package/dist/services/tenant-state.js.map +1 -1
  283. package/dist/state-store.d.ts +4 -0
  284. package/dist/state-store.d.ts.map +1 -1
  285. package/dist/state-store.js +15 -0
  286. package/dist/state-store.js.map +1 -1
  287. package/dist/status-drilldown.d.ts +24 -0
  288. package/dist/status-drilldown.d.ts.map +1 -0
  289. package/dist/status-drilldown.js +50 -0
  290. package/dist/status-drilldown.js.map +1 -0
  291. package/dist/tenant-state.d.ts.map +1 -1
  292. package/dist/tenant-state.js +3 -2
  293. package/dist/tenant-state.js.map +1 -1
  294. package/dist/token-key-custody.d.ts +91 -0
  295. package/dist/token-key-custody.d.ts.map +1 -0
  296. package/dist/token-key-custody.js +375 -0
  297. package/dist/token-key-custody.js.map +1 -0
  298. package/package.json +13 -14
@@ -0,0 +1,231 @@
1
+ // ADR-022 T02 — no-mutation link continuity preflight.
2
+ //
3
+ // Before `hs-x link` rewrites ANYTHING for an already-installed project, this
4
+ // preflight proves continuity is possible — with zero mutations. It reads:
5
+ //
6
+ // 1. the local v2 runtime binding record(s) under the claimed owner
7
+ // (every project / environment / HubSpot app),
8
+ // 2. owner meta (corrupt state fails, absence is recorded, not fatal),
9
+ // 3. the INSTALL_KV namespace for each binding (read-only Cloudflare
10
+ // metadata lookup: exists + id/name match),
11
+ // 4. token-key custody resolvability + canary decryptability for each
12
+ // binding (via the T01 primitives — read-only, typed errors),
13
+ // 5. the Worker names the active deploy records (what link must preserve).
14
+ //
15
+ // Success returns a deterministic, REDACTED plan: Worker names, KV namespace
16
+ // ids, secret NAMES — never key bytes, never the sealed canary. Failure of any
17
+ // check throws a typed `CliError` before the caller has mutated anything: no
18
+ // control-plane registration, no Cloudflare writes, no store writes, no
19
+ // binding rewrites. The journaled migration that CONSUMES this plan is T03.
20
+ import { Schema, schemas } from '@hs-x/types';
21
+ import { cliError } from './cli-error.js';
22
+ import { createCloudflareKvClient } from './cloudflare-kv.js';
23
+ import { resolveEscrowedTokenKey } from './token-key-custody.js';
24
+ const LINK_PREFLIGHT_CODES = [
25
+ // INSTALL_KV namespace missing, or its id/name no longer match the binding.
26
+ 'HSX_E_LINK_PREFLIGHT_NAMESPACE',
27
+ // Owner meta / binding / deploy records exist but do not parse or contradict
28
+ // their own storage key.
29
+ 'HSX_E_LINK_PREFLIGHT_STATE_CORRUPT',
30
+ // Two bindings claim the same INSTALL_KV namespace or the same custody
31
+ // entry — the continuity plan cannot uniquely attribute the resource.
32
+ 'HSX_E_LINK_PREFLIGHT_AMBIGUOUS',
33
+ // Continuity cannot be PROVEN (e.g. `worker-secret-only` custody) — the
34
+ // preflight fails closed rather than letting link proceed unproven.
35
+ 'HSX_E_LINK_PREFLIGHT_UNPROVEN',
36
+ ];
37
+ function preflightError(code, detail) {
38
+ // The bespoke link JSON renders only code+message, so the zero-mutation
39
+ // guarantee rides in the message text where every output mode shows it.
40
+ return cliError(code, `${detail} Link made no changes.`);
41
+ }
42
+ /**
43
+ * Read-only Cloudflare KV namespace metadata lookup:
44
+ * `GET /client/v4/accounts/{account}/storage/kv/namespaces/{id}`.
45
+ * `undefined` = the namespace does not exist. Transport / auth failures throw
46
+ * `HSX_E_API_NETWORK` (they are not evidence of a missing namespace).
47
+ */
48
+ export async function fetchCloudflareKvNamespace(input) {
49
+ const fetchImpl = input.fetchImpl ?? fetch;
50
+ const response = await fetchImpl(new URL(`/client/v4/accounts/${encodeURIComponent(input.accountId)}/storage/kv/namespaces/${encodeURIComponent(input.namespaceId)}`, input.baseUrl ?? 'https://api.cloudflare.com'), { headers: { authorization: `Bearer ${input.apiToken}` } });
51
+ if (response.status === 404)
52
+ return undefined;
53
+ if (!response.ok) {
54
+ const detail = await response.text().catch(() => '');
55
+ throw cliError('HSX_E_API_NETWORK', `Cloudflare KV namespace lookup failed (${response.status})${detail ? `: ${detail.slice(0, 160)}` : ''}`);
56
+ }
57
+ const body = (await response.json().catch(() => undefined));
58
+ if (!body?.result?.id)
59
+ return undefined;
60
+ return { id: body.result.id, title: body.result.title ?? '' };
61
+ }
62
+ const BINDING_KEY_RE = /^owners\/([^/]+)\/projects\/([^/]+)\/bindings\/([^/]+)\/([^/]+)$/;
63
+ /**
64
+ * Run the ADR-022 continuity preflight for one owner prefix. Read-only by
65
+ * construction: the KV surface exposes only get/list, the namespace lookup is
66
+ * a metadata GET, and custody resolution is the T01 read-only primitive.
67
+ * Throws typed `CliError`s (the link-preflight codes above, or the T01
68
+ * token-key-custody codes); returns the redacted plan on success.
69
+ */
70
+ export async function runLinkPreflight(input) {
71
+ const priorOwnerId = input.priorOwnerId;
72
+ const kv = input.kv ?? makeReadOnlyKv(input);
73
+ const getNamespace = input.getNamespace ??
74
+ ((namespaceId) => fetchCloudflareKvNamespace({
75
+ accountId: input.pointer.cloudflareAccountId,
76
+ apiToken: requireApiToken(input.apiToken),
77
+ namespaceId,
78
+ ...(input.baseUrl ? { baseUrl: input.baseUrl } : {}),
79
+ }));
80
+ // ── 1. Owner meta: absence is recorded; corruption fails. ────────────────
81
+ const ownerMetaKey = `owners/${priorOwnerId}/meta`;
82
+ const rawOwnerMeta = await kv.get(ownerMetaKey);
83
+ let ownerMetaPresent = false;
84
+ if (rawOwnerMeta !== undefined) {
85
+ const meta = decodeOr(schemas.LocalOwnerMeta, rawOwnerMeta, ownerMetaKey);
86
+ if (meta.ownerId !== priorOwnerId) {
87
+ throw preflightError('HSX_E_LINK_PREFLIGHT_STATE_CORRUPT', `Owner meta at ${ownerMetaKey} names ownerId ${meta.ownerId}, not ${priorOwnerId}.`);
88
+ }
89
+ ownerMetaPresent = true;
90
+ }
91
+ // ── 2. Enumerate + decode every v2 binding record under the owner. ───────
92
+ const projectKeys = await kv.list(`owners/${priorOwnerId}/projects/`);
93
+ const bindingKeys = projectKeys.filter((key) => BINDING_KEY_RE.test(key)).sort();
94
+ const bindings = [];
95
+ for (const key of bindingKeys) {
96
+ const raw = await kv.get(key);
97
+ if (raw === undefined) {
98
+ throw preflightError('HSX_E_LINK_PREFLIGHT_STATE_CORRUPT', `Binding key ${key} is listed but has no readable value.`);
99
+ }
100
+ const record = decodeOr(schemas.LocalAppRuntimeBinding, raw, key);
101
+ const match = BINDING_KEY_RE.exec(key);
102
+ const [, keyOwner, keyProject, keyEnvironment, keyAppId] = match ?? [];
103
+ if (record.ownerId !== keyOwner ||
104
+ record.projectId !== keyProject ||
105
+ record.environment !== keyEnvironment ||
106
+ String(record.hubSpotAppId) !== keyAppId) {
107
+ throw preflightError('HSX_E_LINK_PREFLIGHT_STATE_CORRUPT', `Binding at ${key} contradicts its storage key (record identity: ${record.ownerId}/${record.projectId}/${record.environment}/${record.hubSpotAppId}).`);
108
+ }
109
+ bindings.push({ key, record });
110
+ }
111
+ // ── 3. Ambiguity: a namespace or custody entry claimed twice cannot be ───
112
+ // uniquely attributed by the migration plan.
113
+ failOnDuplicate(bindings.map(({ key, record }) => ({ key, value: record.installKvNamespaceId })), 'INSTALL_KV namespace');
114
+ failOnDuplicate(bindings.flatMap(({ key, record }) => record.tokenKeyCustody.kind === 'escrowed'
115
+ ? [{ key, value: record.tokenKeyCustody.custodyId }]
116
+ : []), 'token-key custody entry');
117
+ // ── 4 + 5. Per binding: INSTALL_KV namespace + custody canary proof. ─────
118
+ const planBindings = [];
119
+ for (const { key, record } of bindings) {
120
+ const namespace = await getNamespace(record.installKvNamespaceId);
121
+ if (!namespace) {
122
+ throw preflightError('HSX_E_LINK_PREFLIGHT_NAMESPACE', `INSTALL_KV namespace ${record.installKvNamespaceId} (${record.installKvNamespaceName}) referenced by ${key} does not exist on Cloudflare account ${input.pointer.cloudflareAccountId}.`);
123
+ }
124
+ if (namespace.id !== record.installKvNamespaceId) {
125
+ throw preflightError('HSX_E_LINK_PREFLIGHT_NAMESPACE', `INSTALL_KV namespace lookup for ${record.installKvNamespaceId} returned a different id (${namespace.id}).`);
126
+ }
127
+ if (namespace.title !== record.installKvNamespaceName) {
128
+ throw preflightError('HSX_E_LINK_PREFLIGHT_NAMESPACE', `INSTALL_KV namespace ${record.installKvNamespaceId} is named "${namespace.title}" on Cloudflare but the binding at ${key} records "${record.installKvNamespaceName}".`);
129
+ }
130
+ if (record.tokenKeyCustody.kind !== 'escrowed') {
131
+ throw preflightError('HSX_E_LINK_PREFLIGHT_UNPROVEN', `The binding at ${key} records token-key custody "${record.tokenKeyCustody.kind}": the HSX_TOKEN_KEY exists only as the deployed Worker's write-only secret, so continuity cannot be proven from this machine.`);
132
+ }
133
+ // T01 read-only proof: retrieve the escrowed key and open the sealed
134
+ // canary. The key bytes are discarded immediately — the plan carries only
135
+ // the custody REFERENCE and the fact the proof succeeded.
136
+ await resolveEscrowedTokenKey({
137
+ custody: record.tokenKeyCustody,
138
+ ...(input.custodyAdapter ? { adapter: input.custodyAdapter } : {}),
139
+ });
140
+ planBindings.push({
141
+ projectId: record.projectId,
142
+ environment: record.environment,
143
+ hubSpotAppId: record.hubSpotAppId,
144
+ workerNames: await readActiveWorkerNames(kv, priorOwnerId, record),
145
+ installKvNamespaceId: record.installKvNamespaceId,
146
+ installKvNamespaceName: record.installKvNamespaceName,
147
+ tokenKeySecretName: record.tokenKeySecretName,
148
+ tokenKeyCustody: {
149
+ kind: 'escrowed',
150
+ mechanism: record.tokenKeyCustody.mechanism,
151
+ custodyId: record.tokenKeyCustody.custodyId,
152
+ canaryProven: true,
153
+ },
154
+ });
155
+ }
156
+ return {
157
+ plan: 'link-preflight',
158
+ schemaVersion: 1,
159
+ priorOwnerId,
160
+ ...(input.newOwnerId ? { newOwnerId: input.newOwnerId } : {}),
161
+ cloudflareAccountId: input.pointer.cloudflareAccountId,
162
+ stateKvNamespaceId: input.pointer.stateKvNamespaceId,
163
+ ownerMetaPresent,
164
+ bindings: planBindings,
165
+ checks: [
166
+ `owner-meta:${ownerMetaPresent ? 'present' : 'absent'}`,
167
+ `bindings:${planBindings.length}`,
168
+ 'install-kv-namespaces:verified',
169
+ 'token-key-custody:proven',
170
+ 'worker-names:resolved',
171
+ ],
172
+ };
173
+ }
174
+ function requireApiToken(apiToken) {
175
+ if (!apiToken) {
176
+ throw cliError('HSX_E_INTERNAL', 'Link preflight needs a Cloudflare API token for read-only namespace lookups.');
177
+ }
178
+ return apiToken;
179
+ }
180
+ function makeReadOnlyKv(input) {
181
+ const client = createCloudflareKvClient({
182
+ accountId: input.pointer.cloudflareAccountId,
183
+ apiToken: requireApiToken(input.apiToken),
184
+ namespaceId: input.pointer.stateKvNamespaceId,
185
+ ...(input.baseUrl ? { baseUrl: input.baseUrl } : {}),
186
+ });
187
+ // Expose ONLY the read surface — the preflight cannot write by construction.
188
+ return {
189
+ get: (key) => client.get(key),
190
+ list: (prefix) => client.list(prefix),
191
+ };
192
+ }
193
+ function decodeOr(schema, raw, key) {
194
+ let parsed;
195
+ try {
196
+ parsed = JSON.parse(raw);
197
+ }
198
+ catch {
199
+ throw preflightError('HSX_E_LINK_PREFLIGHT_STATE_CORRUPT', `The record at ${key} is not valid JSON.`);
200
+ }
201
+ try {
202
+ return Schema.decodeUnknownSync(schema)(parsed);
203
+ }
204
+ catch (cause) {
205
+ throw preflightError('HSX_E_LINK_PREFLIGHT_STATE_CORRUPT', `The record at ${key} does not match its schema: ${cause instanceof Error ? cause.message.split('\n')[0] : String(cause)}.`);
206
+ }
207
+ }
208
+ function failOnDuplicate(entries, what) {
209
+ const seen = new Map();
210
+ for (const { key, value } of entries) {
211
+ const prior = seen.get(value);
212
+ if (prior !== undefined) {
213
+ throw preflightError('HSX_E_LINK_PREFLIGHT_AMBIGUOUS', `Bindings ${prior} and ${key} both claim ${what} ${value} — the continuity plan cannot uniquely attribute it.`);
214
+ }
215
+ seen.set(value, key);
216
+ }
217
+ }
218
+ async function readActiveWorkerNames(kv, ownerId, record) {
219
+ const activeKey = `owners/${ownerId}/projects/${record.projectId}/active/${record.environment}`;
220
+ const rawActive = await kv.get(activeKey);
221
+ if (rawActive === undefined)
222
+ return [];
223
+ const active = decodeOr(schemas.LocalActiveDeploy, rawActive, activeKey);
224
+ const deployKey = `owners/${ownerId}/projects/${record.projectId}/deploys/${active.deployId}`;
225
+ const rawDeploy = await kv.get(deployKey);
226
+ if (rawDeploy === undefined)
227
+ return [];
228
+ const deploy = decodeOr(schemas.LocalDeployEntry, rawDeploy, deployKey);
229
+ return deploy.workerNames;
230
+ }
231
+ //# sourceMappingURL=link-preflight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link-preflight.js","sourceRoot":"","sources":["../src/link-preflight.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { SelectOptions } from './prompt.js';
2
+ export interface LocalProjectCandidate {
3
+ readonly root: string;
4
+ readonly relativePath: string;
5
+ readonly name: string;
6
+ readonly marker: string;
7
+ }
8
+ export interface LocalProjectPickerPrompts {
9
+ readonly select: <T extends string>(options: SelectOptions<T>) => Promise<T | undefined>;
10
+ }
11
+ export declare class LocalProjectPickerCancelled extends Error {
12
+ constructor();
13
+ }
14
+ /**
15
+ * Discover local project roots beneath a workspace directory. The walk is
16
+ * deliberately bounded and never follows symlinks, generated directories, or
17
+ * archived test runs. Once a project marker is found, that directory is a leaf:
18
+ * generated/nested files inside an app cannot become duplicate candidates.
19
+ */
20
+ export declare function discoverLocalProjects(input: {
21
+ readonly root: string;
22
+ readonly markers?: readonly string[];
23
+ readonly maxDepth?: number;
24
+ readonly maxDirectories?: number;
25
+ readonly excludedDirectories?: ReadonlySet<string>;
26
+ }): Promise<readonly LocalProjectCandidate[]>;
27
+ export declare function resolveLocalProject(input: {
28
+ readonly root: string;
29
+ readonly allowPrompt: boolean;
30
+ readonly markers?: readonly string[];
31
+ readonly message?: string;
32
+ readonly prompts?: LocalProjectPickerPrompts;
33
+ }): Promise<LocalProjectCandidate | undefined>;
34
+ //# sourceMappingURL=local-project-picker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-project-picker.d.ts","sourceRoot":"","sources":["../src/local-project-picker.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAejD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,SAAS,MAAM,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;CAC1F;AAED,qBAAa,2BAA4B,SAAQ,KAAK;;CAIrD;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAAC,KAAK,EAAE;IACjD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACpD,GAAG,OAAO,CAAC,SAAS,qBAAqB,EAAE,CAAC,CA+C5C;AAED,wBAAsB,mBAAmB,CAAC,KAAK,EAAE;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,yBAAyB,CAAC;CAC9C,GAAG,OAAO,CAAC,qBAAqB,GAAG,SAAS,CAAC,CAsB7C"}
@@ -0,0 +1,121 @@
1
+ import { readFile, readdir } from 'node:fs/promises';
2
+ import { basename, join, relative, resolve } from 'node:path';
3
+ const DEFAULT_EXCLUDED_DIRECTORIES = new Set([
4
+ '.git',
5
+ '.hs-x',
6
+ '.next',
7
+ '.turbo',
8
+ '.wrangler',
9
+ 'build',
10
+ 'coverage',
11
+ 'dist',
12
+ 'node_modules',
13
+ 'test-runs',
14
+ ]);
15
+ export class LocalProjectPickerCancelled extends Error {
16
+ constructor() {
17
+ super('Cancelled.');
18
+ }
19
+ }
20
+ /**
21
+ * Discover local project roots beneath a workspace directory. The walk is
22
+ * deliberately bounded and never follows symlinks, generated directories, or
23
+ * archived test runs. Once a project marker is found, that directory is a leaf:
24
+ * generated/nested files inside an app cannot become duplicate candidates.
25
+ */
26
+ export async function discoverLocalProjects(input) {
27
+ const workspaceRoot = resolve(input.root);
28
+ const markers = input.markers ?? ['hsx.config.ts'];
29
+ const maxDepth = input.maxDepth ?? 4;
30
+ const maxDirectories = input.maxDirectories ?? 500;
31
+ const excluded = input.excludedDirectories ?? DEFAULT_EXCLUDED_DIRECTORIES;
32
+ const queue = [
33
+ { directory: workspaceRoot, depth: 0 },
34
+ ];
35
+ const candidates = [];
36
+ let visited = 0;
37
+ while (queue.length > 0 && visited < maxDirectories) {
38
+ const current = queue.shift();
39
+ if (!current)
40
+ break;
41
+ visited += 1;
42
+ let entries;
43
+ try {
44
+ entries = await readdir(current.directory, { withFileTypes: true });
45
+ }
46
+ catch {
47
+ continue;
48
+ }
49
+ const names = new Set(entries.map((entry) => entry.name));
50
+ const marker = markers.find((name) => names.has(name));
51
+ if (marker) {
52
+ candidates.push({
53
+ root: current.directory,
54
+ relativePath: relative(workspaceRoot, current.directory) || '.',
55
+ name: await readCandidateName(current.directory, marker),
56
+ marker,
57
+ });
58
+ continue;
59
+ }
60
+ if (current.depth >= maxDepth)
61
+ continue;
62
+ for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
63
+ if (!entry.isDirectory() || entry.isSymbolicLink() || excluded.has(entry.name))
64
+ continue;
65
+ queue.push({ directory: join(current.directory, entry.name), depth: current.depth + 1 });
66
+ }
67
+ }
68
+ return candidates.sort((left, right) => left.relativePath.localeCompare(right.relativePath) || left.name.localeCompare(right.name));
69
+ }
70
+ export async function resolveLocalProject(input) {
71
+ const projects = await discoverLocalProjects({
72
+ root: input.root,
73
+ ...(input.markers ? { markers: input.markers } : {}),
74
+ });
75
+ const direct = projects.find((project) => project.relativePath === '.');
76
+ if (direct)
77
+ return direct;
78
+ if (!input.allowPrompt)
79
+ return undefined;
80
+ if (projects.length === 0)
81
+ return undefined;
82
+ if (projects.length === 1)
83
+ return projects[0];
84
+ if (!input.prompts)
85
+ return undefined;
86
+ const selected = await input.prompts.select({
87
+ message: input.message ?? 'Which local project?',
88
+ options: projects.map((project) => ({
89
+ value: project.root,
90
+ label: project.name,
91
+ description: project.relativePath,
92
+ })),
93
+ });
94
+ if (selected === undefined)
95
+ throw new LocalProjectPickerCancelled();
96
+ return projects.find((project) => project.root === selected);
97
+ }
98
+ async function readCandidateName(root, marker) {
99
+ try {
100
+ const source = await readFile(join(root, marker), 'utf8');
101
+ if (marker === 'hsx.config.ts') {
102
+ const name = /\bname\s*:\s*["'`]([^"'`]+)["'`]/.exec(source)?.[1]?.trim();
103
+ if (name)
104
+ return name;
105
+ }
106
+ else if (marker === 'hsproject.json' || marker === 'migration.json') {
107
+ const parsed = JSON.parse(source);
108
+ const legacyApp = typeof parsed.legacyApp === 'object' && parsed.legacyApp !== null
109
+ ? parsed.legacyApp
110
+ : undefined;
111
+ const name = [parsed.name, parsed.appName, parsed.projectName, legacyApp?.name].find((value) => typeof value === 'string' && value.trim().length > 0);
112
+ if (name)
113
+ return name.trim();
114
+ }
115
+ }
116
+ catch {
117
+ // Fall back to the directory name for unreadable or malformed markers.
118
+ }
119
+ return basename(root);
120
+ }
121
+ //# sourceMappingURL=local-project-picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-project-picker.js","sourceRoot":"","sources":["../src/local-project-picker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { SystemType } from '@hs-x/hubspot-cli';
2
+ import { promptMultiSelect, promptSelect } from './prompt.js';
3
+ export type InteractiveLogSource = 'all' | 'workers' | 'hubspot';
4
+ export interface InteractiveLogsProject {
5
+ readonly id: string;
6
+ readonly displayName: string;
7
+ }
8
+ export interface InteractiveLogsSelection {
9
+ readonly projectId: string;
10
+ readonly source: InteractiveLogSource;
11
+ readonly systemTypes?: readonly SystemType[];
12
+ readonly sinceMinutes: number;
13
+ readonly follow: boolean;
14
+ readonly errorsOnly: boolean;
15
+ }
16
+ type Select = typeof promptSelect;
17
+ type MultiSelect = typeof promptMultiSelect;
18
+ export interface InteractiveLogsPromptInput {
19
+ readonly projects: readonly InteractiveLogsProject[];
20
+ readonly currentProjectId?: string;
21
+ /** A project already chosen by the shared operations picker. */
22
+ readonly selectedProjectId?: string;
23
+ /** Project whose HubSpot app binding is available from the current directory. */
24
+ readonly hubspotProjectId?: string;
25
+ }
26
+ export interface InteractiveLogsPromptDependencies {
27
+ readonly interactive?: boolean;
28
+ readonly select?: Select;
29
+ readonly multiSelect?: MultiSelect;
30
+ }
31
+ /**
32
+ * A short, progressive setup for a bare `hs-x logs`. Flags remain the complete,
33
+ * deterministic interface; this only chooses the initial view for a TTY.
34
+ */
35
+ export declare function promptInteractiveLogsSelection(input: InteractiveLogsPromptInput, deps?: InteractiveLogsPromptDependencies): Promise<InteractiveLogsSelection | undefined>;
36
+ export {};
37
+ //# sourceMappingURL=logs-interactive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs-interactive.d.ts","sourceRoot":"","sources":["../src/logs-interactive.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGpD,OAAO,EAAiB,iBAAiB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE7E,MAAM,MAAM,oBAAoB,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,CAAC;AAEjE,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;IACtC,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC7C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAED,KAAK,MAAM,GAAG,OAAO,YAAY,CAAC;AAClC,KAAK,WAAW,GAAG,OAAO,iBAAiB,CAAC;AAE5C,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,QAAQ,EAAE,SAAS,sBAAsB,EAAE,CAAC;IACrD,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,gEAAgE;IAChE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,iFAAiF;IACjF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,iCAAiC;IAChD,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;CACpC;AAoBD;;;GAGG;AACH,wBAAsB,8BAA8B,CAClD,KAAK,EAAE,0BAA0B,EACjC,IAAI,GAAE,iCAAsC,GAC3C,OAAO,CAAC,wBAAwB,GAAG,SAAS,CAAC,CAqF/C"}
@@ -0,0 +1,110 @@
1
+ import { HUBSPOT_LOG_SYSTEM_TYPES } from './hubspot-app-logs.js';
2
+ import { ProjectPickerCancelled, resolveProjectSelection } from './project-picker.js';
3
+ import { isInteractive, promptMultiSelect, promptSelect } from './prompt.js';
4
+ const TYPE_LABELS = {
5
+ WEBHOOKS: { label: 'Webhooks', description: 'Webhook deliveries and failures' },
6
+ API_CALL: { label: 'API calls', description: 'App API requests' },
7
+ SERVERLESS_EXECUTION: { label: 'Serverless functions', description: 'Function executions' },
8
+ CRM_EXTENSIBILITY_CARD: { label: 'CRM cards', description: 'Modern CRM card activity' },
9
+ CRM_LEGACY_CARD: { label: 'Legacy CRM cards', description: 'Legacy card activity' },
10
+ EXTENSION_LOG: { label: 'Frontend logs', description: 'Production UI logger output' },
11
+ EXTENSION_RENDER: { label: 'Extension renders', description: 'UI extension render activity' },
12
+ APP_SETTINGS: { label: 'App settings', description: 'App settings activity' },
13
+ PROXY_EXECUTION: { label: 'Proxy executions', description: 'Proxy request activity' },
14
+ SERVERLESS_GATEWAY_EXECUTION: {
15
+ label: 'Serverless gateway',
16
+ description: 'Gateway execution activity',
17
+ },
18
+ ACCEPTANCE_TEST: { label: 'Acceptance tests', description: 'HubSpot acceptance-test activity' },
19
+ OAUTH_AUTHORIZATION: { label: 'OAuth', description: 'Authorization activity' },
20
+ };
21
+ /**
22
+ * A short, progressive setup for a bare `hs-x logs`. Flags remain the complete,
23
+ * deterministic interface; this only chooses the initial view for a TTY.
24
+ */
25
+ export async function promptInteractiveLogsSelection(input, deps = {}) {
26
+ if (!(deps.interactive ?? isInteractive()))
27
+ return undefined;
28
+ const select = deps.select ?? promptSelect;
29
+ const multiSelect = deps.multiSelect ?? promptMultiSelect;
30
+ let projectId = input.selectedProjectId;
31
+ if (!projectId) {
32
+ try {
33
+ projectId = (await resolveProjectSelection({
34
+ accountId: '',
35
+ projects: input.projects,
36
+ ...(input.currentProjectId ? { localProjectId: input.currentProjectId } : {}),
37
+ allowPrompt: true,
38
+ prompts: { select },
39
+ message: 'Which project do you want logs for?',
40
+ promptWhenSingle: true,
41
+ })).id;
42
+ }
43
+ catch (error) {
44
+ if (error instanceof ProjectPickerCancelled)
45
+ return undefined;
46
+ throw error;
47
+ }
48
+ }
49
+ const hasLocalHubSpotBinding = input.hubspotProjectId === projectId;
50
+ const source = await select({
51
+ message: 'Where do you want to look?',
52
+ default: hasLocalHubSpotBinding ? 'all' : 'workers',
53
+ options: hasLocalHubSpotBinding
54
+ ? [
55
+ {
56
+ value: 'all',
57
+ label: 'Everything',
58
+ description: 'Workers and HubSpot in one timeline',
59
+ },
60
+ { value: 'workers', label: 'Workers', description: 'HS-X runtime requests and logs' },
61
+ {
62
+ value: 'hubspot',
63
+ label: 'HubSpot',
64
+ description: 'App, extension, webhook, and OAuth logs',
65
+ },
66
+ ]
67
+ : [
68
+ {
69
+ value: 'workers',
70
+ label: 'Workers',
71
+ description: 'HubSpot app logs require that project’s local binding',
72
+ },
73
+ ],
74
+ });
75
+ if (!source)
76
+ return undefined;
77
+ let systemTypes;
78
+ if (source !== 'workers') {
79
+ systemTypes = await multiSelect({
80
+ message: 'Which HubSpot logs do you want to see?',
81
+ options: HUBSPOT_LOG_SYSTEM_TYPES.map((value) => ({ value, ...TYPE_LABELS[value] })),
82
+ initial: [...HUBSPOT_LOG_SYSTEM_TYPES],
83
+ minSelected: 1,
84
+ });
85
+ if (!systemTypes)
86
+ return undefined;
87
+ }
88
+ const view = await select({
89
+ message: 'What do you want to see?',
90
+ default: '15m',
91
+ options: [
92
+ { value: '15m', label: 'Last 15 minutes' },
93
+ { value: 'live', label: 'Live logs', description: 'Recent context, then keep following' },
94
+ { value: '60m', label: 'Last hour' },
95
+ { value: '1440m', label: 'Last 24 hours' },
96
+ { value: 'errors-60m', label: 'Errors in the last hour' },
97
+ ],
98
+ });
99
+ if (!view)
100
+ return undefined;
101
+ return {
102
+ projectId,
103
+ source,
104
+ ...(systemTypes ? { systemTypes } : {}),
105
+ sinceMinutes: view === '15m' || view === 'live' ? 15 : view === '1440m' ? 1440 : 60,
106
+ follow: view === 'live',
107
+ errorsOnly: view === 'errors-60m',
108
+ };
109
+ }
110
+ //# sourceMappingURL=logs-interactive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs-interactive.js","sourceRoot":"","sources":["../src/logs-interactive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface CliOutputFlags {
2
+ readonly json: boolean;
3
+ readonly jsonStream: boolean;
4
+ readonly quiet: boolean;
5
+ readonly verbose: boolean;
6
+ readonly debug: boolean;
7
+ }
8
+ export declare function resolveCliOutputFlags(argv: readonly string[]): CliOutputFlags;
9
+ export declare function withCliOutputFlags<T>(flags: CliOutputFlags, thunk: () => T): T;
10
+ export declare function currentCliOutputFlags(): CliOutputFlags;
11
+ export declare function currentReporterArgv(): readonly string[];
12
+ export declare function isMachineOutput(): boolean;
13
+ //# sourceMappingURL=output-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output-context.d.ts","sourceRoot":"","sources":["../src/output-context.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAYD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,cAAc,CAQ7E;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,CAE9E;AAED,wBAAgB,qBAAqB,IAAI,cAAc,CAEtD;AAED,wBAAgB,mBAAmB,IAAI,SAAS,MAAM,EAAE,CAWvD;AAED,wBAAgB,eAAe,IAAI,OAAO,CAGzC"}
@@ -0,0 +1,46 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ const DEFAULT_FLAGS = {
3
+ json: false,
4
+ jsonStream: false,
5
+ quiet: false,
6
+ verbose: false,
7
+ debug: false,
8
+ };
9
+ const storage = new AsyncLocalStorage();
10
+ export function resolveCliOutputFlags(argv) {
11
+ return {
12
+ json: argv.includes('--json'),
13
+ jsonStream: argv.includes('--json-stream'),
14
+ quiet: argv.includes('--quiet') || argv.includes('-q'),
15
+ verbose: argv.includes('--verbose'),
16
+ debug: argv.includes('--debug'),
17
+ };
18
+ }
19
+ export function withCliOutputFlags(flags, thunk) {
20
+ return storage.run(flags, thunk);
21
+ }
22
+ export function currentCliOutputFlags() {
23
+ return storage.getStore() ?? DEFAULT_FLAGS;
24
+ }
25
+ export function currentReporterArgv() {
26
+ const flags = currentCliOutputFlags();
27
+ const argv = [];
28
+ // runCli rejects dual machine flags before command execution; reporters only
29
+ // ever receive one of these modes during a valid invocation.
30
+ if (flags.json)
31
+ argv.push('--json');
32
+ if (flags.jsonStream)
33
+ argv.push('--json-stream');
34
+ if (flags.quiet)
35
+ argv.push('--quiet');
36
+ if (flags.verbose)
37
+ argv.push('--verbose');
38
+ if (flags.debug)
39
+ argv.push('--debug');
40
+ return argv;
41
+ }
42
+ export function isMachineOutput() {
43
+ const flags = currentCliOutputFlags();
44
+ return flags.json || flags.jsonStream;
45
+ }
46
+ //# sourceMappingURL=output-context.js.map