t3code-cli 0.10.0 → 0.12.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 (328) hide show
  1. package/README.md +75 -11
  2. package/dist/application.js +2 -2
  3. package/dist/auth.js +1 -1
  4. package/dist/bin.js +86754 -2675
  5. package/dist/cli.js +15 -2
  6. package/dist/config.js +120 -2
  7. package/dist/connection.js +2 -12
  8. package/dist/index.js +1 -1
  9. package/dist/node.js +6 -0
  10. package/dist/orchestration.js +2 -2
  11. package/dist/rpc.js +2 -2
  12. package/dist/runtime.js +2 -2
  13. package/dist/shared.js +43850 -38040
  14. package/dist/src/application/actions.d.ts +25 -0
  15. package/dist/src/application/index.d.ts +3 -2
  16. package/dist/src/application/layer.d.ts +99 -842
  17. package/dist/src/application/model-selection.d.ts +17 -2
  18. package/dist/src/application/models.d.ts +1 -87
  19. package/dist/src/application/project-commands.d.ts +31 -2
  20. package/dist/src/application/projects.d.ts +15 -137
  21. package/dist/src/application/service.d.ts +147 -5
  22. package/dist/src/application/shell-sequence.d.ts +5 -4
  23. package/dist/src/application/terminals.d.ts +66 -0
  24. package/dist/src/application/thread-commands.d.ts +48 -1
  25. package/dist/src/application/thread-update.d.ts +8 -0
  26. package/dist/src/application/thread-wait.d.ts +4 -6
  27. package/dist/src/application/threads.d.ts +36 -14
  28. package/dist/src/auth/error.d.ts +2 -1
  29. package/dist/src/auth/index.d.ts +1 -1
  30. package/dist/src/auth/layer.d.ts +34 -6
  31. package/dist/src/auth/local-base-dir.d.ts +5 -2
  32. package/dist/src/auth/local-origin.d.ts +3 -3
  33. package/dist/src/auth/local-token.d.ts +3 -3
  34. package/dist/src/auth/service.d.ts +15 -3
  35. package/dist/src/auth/type.d.ts +40 -1
  36. package/dist/src/cli/env/flag.d.ts +2 -0
  37. package/dist/src/cli/env/index.d.ts +2 -0
  38. package/dist/src/cli/env/selection-layer.d.ts +3 -0
  39. package/dist/src/cli/flags.d.ts +5 -0
  40. package/dist/src/cli/format/index.d.ts +1 -0
  41. package/dist/src/cli/format/output.d.ts +12 -0
  42. package/dist/src/cli/index.d.ts +4 -0
  43. package/dist/src/cli/runtime/index.d.ts +1 -0
  44. package/dist/src/cli/runtime/service.d.ts +16 -0
  45. package/dist/src/{scope → cli/scope}/resolve.d.ts +5 -4
  46. package/dist/src/config/config.d.ts +49 -0
  47. package/dist/src/config/credential/cipher-node.d.ts +3 -0
  48. package/dist/src/config/credential/cipher-web.d.ts +3 -0
  49. package/dist/src/config/credential/cipher.d.ts +29 -0
  50. package/dist/src/config/credential/env.d.ts +3 -0
  51. package/dist/src/config/credential/error.d.ts +8 -0
  52. package/dist/src/config/credential/index.d.ts +6 -0
  53. package/dist/src/config/credential/service.d.ts +34 -0
  54. package/dist/src/config/env/env.d.ts +55 -0
  55. package/dist/src/config/env/index.d.ts +2 -0
  56. package/dist/src/{layout/base-dir.d.ts → config/env/layout.d.ts} +0 -1
  57. package/dist/src/config/environment-name/index.d.ts +1 -0
  58. package/dist/src/config/environment-name/name.d.ts +10 -0
  59. package/dist/src/config/error.d.ts +4 -11
  60. package/dist/src/config/index.d.ts +10 -5
  61. package/dist/src/config/keystore/error.d.ts +8 -0
  62. package/dist/src/config/keystore/file.d.ts +9 -0
  63. package/dist/src/config/keystore/index.d.ts +4 -0
  64. package/dist/src/config/keystore/keyring-node.d.ts +4 -0
  65. package/dist/src/config/keystore/service.d.ts +33 -0
  66. package/dist/src/config/paths/index.d.ts +1 -0
  67. package/dist/src/config/paths/paths.d.ts +6 -0
  68. package/dist/src/config/persist/file-mode.d.ts +4 -0
  69. package/dist/src/config/persist/migration.d.ts +68 -0
  70. package/dist/src/config/persist/persist.d.ts +40 -0
  71. package/dist/src/config/persist/schema.d.ts +68 -0
  72. package/dist/src/config/resolve/resolve.d.ts +40 -0
  73. package/dist/src/config/selection/index.d.ts +1 -0
  74. package/dist/src/config/selection/resolve.d.ts +4 -0
  75. package/dist/src/config/selection/service.d.ts +10 -0
  76. package/dist/src/config/types.d.ts +36 -0
  77. package/dist/src/config/url/error.d.ts +10 -0
  78. package/dist/src/config/url/index.d.ts +2 -0
  79. package/dist/src/connection/index.d.ts +0 -1
  80. package/dist/src/contracts/index.d.ts +1 -1
  81. package/dist/src/domain/error.d.ts +27 -1
  82. package/dist/src/domain/helpers.d.ts +8 -2
  83. package/dist/src/domain/model-config.d.ts +30 -1
  84. package/dist/src/domain/thread-activities.d.ts +1 -1
  85. package/dist/src/domain/thread-lifecycle.d.ts +3 -2
  86. package/dist/src/index.d.ts +1 -2
  87. package/dist/src/{connection/node.d.ts → node/connection.d.ts} +1 -1
  88. package/dist/src/node/index.d.ts +1 -0
  89. package/dist/src/orchestration/index.d.ts +1 -1
  90. package/dist/src/orchestration/layer.d.ts +120 -829
  91. package/dist/src/orchestration/service.d.ts +2 -1
  92. package/dist/src/rpc/error.d.ts +5 -3
  93. package/dist/src/rpc/index.d.ts +5 -1
  94. package/dist/src/rpc/layer.d.ts +1166 -40
  95. package/dist/src/rpc/operation.d.ts +6280 -0
  96. package/dist/src/rpc/ws-group.d.ts +372 -27
  97. package/dist/src/runtime/index.d.ts +1 -2
  98. package/dist/src/runtime/layer.d.ts +12 -8
  99. package/dist/src/t3tools/index.d.ts +1 -1
  100. package/dist/t3tools.js +2 -2
  101. package/package.json +27 -19
  102. package/src/application/actions.test.ts +328 -0
  103. package/src/application/actions.ts +475 -0
  104. package/src/application/index.ts +32 -2
  105. package/src/application/layer.ts +43 -5
  106. package/src/application/model-selection.ts +70 -4
  107. package/src/application/models.ts +14 -14
  108. package/src/application/project-commands.ts +38 -5
  109. package/src/application/projects.ts +49 -20
  110. package/src/application/service.ts +275 -78
  111. package/src/application/shell-sequence.ts +6 -8
  112. package/src/application/terminals.ts +208 -0
  113. package/src/application/thread-commands.test.ts +43 -0
  114. package/src/application/thread-commands.ts +82 -1
  115. package/src/application/thread-update.ts +72 -0
  116. package/src/application/thread-wait.ts +47 -48
  117. package/src/application/threads.test.ts +172 -0
  118. package/src/application/threads.ts +128 -45
  119. package/src/auth/error.ts +2 -1
  120. package/src/auth/index.ts +7 -0
  121. package/src/auth/layer.test-utils.ts +34 -0
  122. package/src/auth/layer.ts +116 -34
  123. package/src/auth/local-base-dir.ts +13 -6
  124. package/src/auth/local-origin.ts +10 -7
  125. package/src/auth/local-token.ts +28 -23
  126. package/src/auth/service.test.ts +200 -0
  127. package/src/auth/service.ts +27 -3
  128. package/src/auth/transport.ts +2 -2
  129. package/src/auth/type.ts +47 -1
  130. package/src/bin.ts +26 -6
  131. package/src/cli/action-format.ts +110 -0
  132. package/src/cli/action.ts +398 -0
  133. package/src/cli/app.ts +8 -0
  134. package/src/cli/auth.ts +76 -23
  135. package/src/cli/env/flag.ts +8 -0
  136. package/src/cli/env/index.ts +2 -0
  137. package/src/cli/env/selection-layer.test.ts +49 -0
  138. package/src/cli/env/selection-layer.ts +27 -0
  139. package/src/cli/env.ts +107 -0
  140. package/src/cli/error.ts +26 -3
  141. package/src/cli/extra-args.test.ts +32 -0
  142. package/src/cli/extra-args.ts +22 -0
  143. package/src/cli/flags.ts +26 -1
  144. package/src/cli/format/auth.ts +92 -0
  145. package/src/cli/format/human.ts +131 -0
  146. package/src/cli/format/index.ts +12 -0
  147. package/src/cli/format/model.ts +29 -0
  148. package/src/cli/format/output.ts +51 -0
  149. package/src/cli/format/project.ts +32 -0
  150. package/src/cli/format/terminal.ts +87 -0
  151. package/src/cli/format/thread.test.ts +34 -0
  152. package/src/cli/format/thread.ts +185 -0
  153. package/src/cli/index.ts +20 -0
  154. package/src/cli/input/layer.ts +20 -0
  155. package/src/cli/input/service.ts +1 -0
  156. package/src/cli/interaction/confirm.ts +64 -0
  157. package/src/cli/interaction/self-action.ts +36 -0
  158. package/src/cli/message-input.ts +1 -1
  159. package/src/cli/model.ts +9 -5
  160. package/src/cli/project.ts +15 -8
  161. package/src/cli/projects/delete.ts +51 -0
  162. package/src/cli/require.ts +9 -7
  163. package/src/cli/runtime/index.ts +1 -0
  164. package/src/cli/runtime/service.ts +28 -0
  165. package/src/{scope → cli/scope}/resolve.ts +11 -9
  166. package/src/cli/terminal/attach.ts +29 -0
  167. package/src/cli/terminal/create.ts +55 -0
  168. package/src/cli/terminal/destroy.ts +62 -0
  169. package/src/cli/terminal/encoding.test.ts +63 -0
  170. package/src/cli/terminal/encoding.ts +23 -0
  171. package/src/cli/terminal/error.ts +14 -0
  172. package/src/cli/terminal/io-node-layer.ts +82 -0
  173. package/src/cli/terminal/io-service.ts +25 -0
  174. package/src/cli/terminal/list.ts +36 -0
  175. package/src/cli/terminal/read.test-utils.ts +48 -0
  176. package/src/cli/terminal/read.test.ts +35 -0
  177. package/src/cli/terminal/read.ts +99 -0
  178. package/src/cli/terminal/scope.ts +35 -0
  179. package/src/cli/terminal/shared.ts +250 -0
  180. package/src/cli/terminal/stream.ts +61 -0
  181. package/src/cli/terminal/wait.test.ts +148 -0
  182. package/src/cli/terminal/wait.ts +223 -0
  183. package/src/cli/terminal/write.test.ts +34 -0
  184. package/src/cli/terminal/write.ts +133 -0
  185. package/src/cli/terminal.ts +26 -0
  186. package/src/cli/thread.ts +8 -0
  187. package/src/cli/threads/approve.ts +11 -7
  188. package/src/cli/threads/archive.ts +23 -25
  189. package/src/cli/threads/callback.ts +6 -4
  190. package/src/cli/threads/delete.ts +67 -0
  191. package/src/cli/threads/interrupt.ts +57 -0
  192. package/src/cli/threads/list.test.ts +71 -0
  193. package/src/cli/threads/list.ts +25 -13
  194. package/src/cli/threads/messages.ts +11 -7
  195. package/src/cli/threads/respond.ts +11 -7
  196. package/src/cli/threads/send.ts +39 -9
  197. package/src/cli/threads/show.ts +11 -7
  198. package/src/cli/threads/start.ts +18 -13
  199. package/src/cli/threads/unarchive.ts +48 -0
  200. package/src/cli/threads/update.ts +155 -0
  201. package/src/cli/threads/wait.ts +11 -7
  202. package/src/cli/wait-events.ts +1 -1
  203. package/src/config/config.ts +260 -0
  204. package/src/config/credential/cipher-node.ts +40 -0
  205. package/src/config/credential/cipher-web.ts +82 -0
  206. package/src/config/credential/cipher.ts +39 -0
  207. package/src/config/credential/env.ts +13 -0
  208. package/src/config/credential/error.ts +9 -0
  209. package/src/config/credential/index.ts +6 -0
  210. package/src/config/credential/service.test-utils.ts +25 -0
  211. package/src/config/credential/service.test.ts +116 -0
  212. package/src/config/credential/service.ts +205 -0
  213. package/src/config/env/env.test-utils.ts +14 -0
  214. package/src/config/env/env.ts +81 -0
  215. package/src/config/env/index.ts +2 -0
  216. package/src/{layout/base-dir.ts → config/env/layout.ts} +0 -9
  217. package/src/config/environment-name/index.ts +7 -0
  218. package/src/config/environment-name/name.test.ts +66 -0
  219. package/src/config/environment-name/name.ts +49 -0
  220. package/src/config/error.ts +6 -8
  221. package/src/config/index.ts +16 -5
  222. package/src/config/keystore/error.ts +9 -0
  223. package/src/config/keystore/file.ts +96 -0
  224. package/src/config/keystore/index.ts +4 -0
  225. package/src/config/keystore/keyring-node.test.ts +12 -0
  226. package/src/config/keystore/keyring-node.ts +100 -0
  227. package/src/config/keystore/service.test-utils.ts +15 -0
  228. package/src/config/keystore/service.test.ts +18 -0
  229. package/src/config/keystore/service.ts +29 -0
  230. package/src/config/layer.test-utils.ts +45 -0
  231. package/src/config/layer.test.ts +209 -0
  232. package/src/config/paths/index.ts +1 -0
  233. package/src/config/paths/paths.ts +36 -0
  234. package/src/config/persist/file-mode.ts +21 -0
  235. package/src/config/persist/migration.test.ts +71 -0
  236. package/src/config/persist/migration.ts +82 -0
  237. package/src/config/persist/persist.test.ts +113 -0
  238. package/src/config/persist/persist.ts +65 -0
  239. package/src/config/persist/schema.ts +37 -0
  240. package/src/config/platform.test-utils.ts +20 -0
  241. package/src/config/resolve/resolve.test-utils.ts +20 -0
  242. package/src/config/resolve/resolve.test.ts +137 -0
  243. package/src/config/resolve/resolve.ts +104 -0
  244. package/src/config/selection/index.ts +1 -0
  245. package/src/config/selection/resolve.ts +14 -0
  246. package/src/config/selection/service.ts +29 -0
  247. package/src/config/temp-home.test-utils.ts +7 -0
  248. package/src/config/types.ts +49 -0
  249. package/src/config/url/error.ts +8 -0
  250. package/src/config/url/index.ts +7 -0
  251. package/src/config/url/url.test.ts +31 -0
  252. package/src/connection/index.ts +0 -1
  253. package/src/contracts/index.ts +1 -1
  254. package/src/domain/error.ts +39 -1
  255. package/src/domain/helpers.test.ts +1 -1
  256. package/src/domain/helpers.ts +1 -1
  257. package/src/domain/model-config.ts +5 -1
  258. package/src/domain/thread-activities.test.ts +1 -1
  259. package/src/domain/thread-activities.ts +1 -1
  260. package/src/domain/thread-lifecycle.test.ts +1 -1
  261. package/src/domain/thread-lifecycle.ts +15 -1
  262. package/src/effect.test-utils.ts +25 -0
  263. package/src/index.ts +1 -1
  264. package/src/{connection/node.ts → node/connection.ts} +1 -1
  265. package/src/node/index.ts +1 -0
  266. package/src/orchestration/index.ts +1 -1
  267. package/src/orchestration/layer.ts +34 -86
  268. package/src/orchestration/service.ts +5 -1
  269. package/src/rpc/error.ts +12 -2
  270. package/src/rpc/index.ts +5 -1
  271. package/src/rpc/layer.ts +1 -1
  272. package/src/rpc/operation.ts +83 -0
  273. package/src/rpc/ws-group.ts +25 -1
  274. package/src/runtime/index.ts +2 -1
  275. package/src/runtime/layer.test-utils.ts +32 -0
  276. package/src/runtime/layer.test.ts +66 -0
  277. package/src/runtime/layer.ts +22 -11
  278. package/src/t3tools/index.ts +1 -1
  279. package/src/types/marked-terminal.d.ts +11 -0
  280. package/dist/layout.js +0 -2
  281. package/dist/scope.js +0 -2
  282. package/dist/src/cli/output-format.d.ts +0 -9
  283. package/dist/src/config/layer.d.ts +0 -22
  284. package/dist/src/config/service.d.ts +0 -22
  285. package/dist/src/environment/layer.d.ts +0 -3
  286. package/dist/src/environment/service.d.ts +0 -12
  287. package/dist/src/layout/index.d.ts +0 -1
  288. package/dist/upstream-t3code/packages/contracts/src/auth.d.ts +0 -441
  289. package/dist/upstream-t3code/packages/contracts/src/baseSchemas.d.ts +0 -38
  290. package/dist/upstream-t3code/packages/contracts/src/desktopBootstrap.d.ts +0 -14
  291. package/dist/upstream-t3code/packages/contracts/src/editor.d.ts +0 -124
  292. package/dist/upstream-t3code/packages/contracts/src/environment.d.ts +0 -64
  293. package/dist/upstream-t3code/packages/contracts/src/environmentHttp.d.ts +0 -785
  294. package/dist/upstream-t3code/packages/contracts/src/filesystem.d.ts +0 -26
  295. package/dist/upstream-t3code/packages/contracts/src/git.d.ts +0 -500
  296. package/dist/upstream-t3code/packages/contracts/src/index.d.ts +0 -25
  297. package/dist/upstream-t3code/packages/contracts/src/ipc.d.ts +0 -496
  298. package/dist/upstream-t3code/packages/contracts/src/keybindings.d.ts +0 -133
  299. package/dist/upstream-t3code/packages/contracts/src/model.d.ts +0 -112
  300. package/dist/upstream-t3code/packages/contracts/src/orchestration.d.ts +0 -7338
  301. package/dist/upstream-t3code/packages/contracts/src/project.d.ts +0 -45
  302. package/dist/upstream-t3code/packages/contracts/src/provider.d.ts +0 -130
  303. package/dist/upstream-t3code/packages/contracts/src/providerInstance.d.ts +0 -99
  304. package/dist/upstream-t3code/packages/contracts/src/providerRuntime.d.ts +0 -4450
  305. package/dist/upstream-t3code/packages/contracts/src/relay.d.ts +0 -1262
  306. package/dist/upstream-t3code/packages/contracts/src/relayClient.d.ts +0 -48
  307. package/dist/upstream-t3code/packages/contracts/src/remoteAccess.d.ts +0 -45
  308. package/dist/upstream-t3code/packages/contracts/src/review.d.ts +0 -37
  309. package/dist/upstream-t3code/packages/contracts/src/rpc.d.ts +0 -8710
  310. package/dist/upstream-t3code/packages/contracts/src/server.d.ts +0 -2336
  311. package/dist/upstream-t3code/packages/contracts/src/settings.d.ts +0 -292
  312. package/dist/upstream-t3code/packages/contracts/src/sourceControl.d.ts +0 -177
  313. package/dist/upstream-t3code/packages/contracts/src/terminal.d.ts +0 -333
  314. package/dist/upstream-t3code/packages/contracts/src/vcs.d.ts +0 -148
  315. package/src/cli/auth-format.ts +0 -45
  316. package/src/cli/model-format.ts +0 -18
  317. package/src/cli/output-format.ts +0 -41
  318. package/src/cli/project-format.ts +0 -11
  319. package/src/cli/thread-format.ts +0 -121
  320. package/src/config/layer.ts +0 -105
  321. package/src/config/service.ts +0 -26
  322. package/src/environment/layer.ts +0 -12
  323. package/src/environment/service.ts +0 -13
  324. package/src/layout/index.ts +0 -1
  325. /package/dist/src/{scope → cli/scope}/index.d.ts +0 -0
  326. /package/dist/src/config/{url.d.ts → url/url.d.ts} +0 -0
  327. /package/src/{scope → cli/scope}/index.ts +0 -0
  328. /package/src/config/{url.ts → url/url.ts} +0 -0
package/src/auth/layer.ts CHANGED
@@ -1,13 +1,23 @@
1
1
  import * as Effect from "effect/Effect";
2
2
  import * as Layer from "effect/Layer";
3
3
 
4
- import { T3Config } from "../config/service.ts";
4
+ import {
5
+ defaultEnvironmentNameForLocal,
6
+ defaultEnvironmentNameFromUrl,
7
+ } from "../config/environment-name/name.ts";
8
+ import type { EnvironmentSummary, ResolvedConfig } from "../config/types.ts";
9
+ import type { ConfigError } from "../config/error.ts";
10
+ import type { UrlError } from "../config/url/error.ts";
11
+ import { T3Config } from "../config/config.ts";
5
12
  import { AuthConfigError } from "./error.ts";
6
13
  import { T3LocalAuth } from "./local.ts";
7
14
  import { T3AuthPairing } from "./pairing.ts";
8
15
  import { T3Auth } from "./service.ts";
9
16
  import { T3AuthTransport } from "./transport.ts";
10
- import type { AuthConfigInput } from "./type.ts";
17
+ import type { AuthConfigInput, AuthEnvironmentListItem, AuthResolvedConfig } from "./type.ts";
18
+
19
+ const mapConfigError = (error: ConfigError | UrlError) =>
20
+ new AuthConfigError({ message: error.message, cause: error });
11
21
 
12
22
  export const makeT3Auth = Effect.fn("makeT3Auth")(function* () {
13
23
  const config = yield* T3Config;
@@ -16,58 +26,130 @@ export const makeT3Auth = Effect.fn("makeT3Auth")(function* () {
16
26
  const pairing = yield* T3AuthPairing;
17
27
 
18
28
  const status = Effect.fn("T3AuthLive.status")(function* () {
19
- const resolved = yield* config.resolve().pipe(
20
- Effect.catchTags({
21
- ConfigError: (error) =>
22
- Effect.fail(new AuthConfigError({ message: "auth config failed", cause: error })),
23
- UrlError: (error) =>
24
- Effect.fail(new AuthConfigError({ message: "auth config failed", cause: error })),
25
- }),
26
- );
27
- return yield* transport.getSession(resolved);
29
+ const resolved = yield* config.resolve().pipe(Effect.mapError(mapConfigError));
30
+ const session = yield* transport.getSession(resolved);
31
+ return { config: toAuthResolvedConfig(resolved), session } as const;
28
32
  });
29
33
 
30
34
  const issueWebSocketTicket = Effect.fn("T3AuthLive.issueWebSocketTicket")(function* () {
31
- const resolved = yield* config.resolve().pipe(
32
- Effect.catchTags({
33
- ConfigError: (error) =>
34
- Effect.fail(new AuthConfigError({ message: "auth config failed", cause: error })),
35
- UrlError: (error) =>
36
- Effect.fail(new AuthConfigError({ message: "auth config failed", cause: error })),
37
- }),
38
- );
35
+ const resolved = yield* config.resolve().pipe(Effect.mapError(mapConfigError));
39
36
  return yield* transport.issueWebSocketTicket(resolved);
40
37
  });
41
38
 
42
- const writeConfig = Effect.fn("T3AuthLive.writeConfig")(function* (input: AuthConfigInput) {
43
- const existing = yield* config.readStored().pipe(
44
- Effect.catchTags({
45
- ConfigError: (error) =>
46
- Effect.fail(new AuthConfigError({ message: "auth config failed", cause: error })),
47
- }),
48
- );
39
+ const persistEnvironment = Effect.fn("T3AuthLive.persistEnvironment")(function* (input: {
40
+ readonly name: string;
41
+ readonly url: string;
42
+ readonly token: string;
43
+ readonly local: boolean;
44
+ readonly replace?: boolean;
45
+ readonly allowReplace: boolean;
46
+ }) {
47
+ const exists = yield* config.hasEnvironment(input.name).pipe(Effect.mapError(mapConfigError));
48
+ if (exists && !input.allowReplace) {
49
+ return yield* Effect.fail(
50
+ new AuthConfigError({
51
+ message: `environment '${input.name}' already exists: pass --replace`,
52
+ }),
53
+ );
54
+ }
55
+ const makeDefault = exists && input.replace === true;
49
56
  yield* config
50
- .writeStored({
51
- ...existing,
57
+ .upsertEnvironment({
58
+ name: input.name,
52
59
  url: input.url,
53
60
  token: input.token,
54
- ...(input.local !== undefined ? { local: input.local } : {}),
61
+ local: input.local,
62
+ ...(makeDefault ? { makeDefault: true } : {}),
55
63
  })
56
- .pipe(
57
- Effect.catchTags({
58
- ConfigError: (error) =>
59
- Effect.fail(new AuthConfigError({ message: "auth config failed", cause: error })),
64
+ .pipe(Effect.mapError(mapConfigError));
65
+ return input.name;
66
+ });
67
+
68
+ const listEnvironments = Effect.fn("T3AuthLive.listEnvironments")(function* () {
69
+ const [environments, activeName] = yield* Effect.all(
70
+ [config.listEnvironments(), config.resolveActiveEnvironmentName()],
71
+ { concurrency: "unbounded" },
72
+ ).pipe(Effect.mapError(mapConfigError));
73
+ return environments.map((environment) => toAuthEnvironmentListItem(environment, activeName));
74
+ });
75
+
76
+ const resolveUnpairTarget = Effect.fn("T3AuthLive.resolveUnpairTarget")(function* (input: {
77
+ readonly name?: string;
78
+ }) {
79
+ if (input.name !== undefined && input.name.length > 0) {
80
+ return input.name;
81
+ }
82
+ const defaultName = yield* config
83
+ .getDefaultEnvironmentName()
84
+ .pipe(Effect.mapError(mapConfigError));
85
+ if (defaultName === undefined) {
86
+ return yield* Effect.fail(
87
+ new AuthConfigError({
88
+ message: "no environment selected: pass --name or run: t3cli env use <name>",
60
89
  }),
61
90
  );
91
+ }
92
+ return defaultName;
62
93
  });
63
94
 
64
95
  return {
65
96
  pair: pairing.pair,
66
97
  local: localAuth.local,
67
- writeConfig,
98
+ writeConfig: (input: AuthConfigInput) =>
99
+ config
100
+ .upsertEnvironment({
101
+ name: input.name,
102
+ url: input.url,
103
+ token: input.token,
104
+ local: input.local,
105
+ ...(input.makeDefault === true ? { makeDefault: true } : {}),
106
+ })
107
+ .pipe(Effect.mapError(mapConfigError)),
108
+ persistEnvironment,
109
+ environmentExists: (name: string) =>
110
+ config.hasEnvironment(name).pipe(Effect.mapError(mapConfigError)),
111
+ defaultNameFromUrl: (url: string) =>
112
+ defaultEnvironmentNameFromUrl(url).pipe(Effect.mapError(mapConfigError)),
113
+ defaultNameForLocal: () => Effect.succeed(defaultEnvironmentNameForLocal()),
114
+ listEnvironments,
115
+ useEnvironment: (name: string) =>
116
+ config
117
+ .setDefaultEnvironment(name)
118
+ .pipe(Effect.mapError(mapConfigError), Effect.as({ name, default: true as const })),
119
+ resolveUnpairTarget,
120
+ unpairEnvironment: (input: { readonly name: string }) =>
121
+ config
122
+ .removeEnvironment(input.name)
123
+ .pipe(
124
+ Effect.mapError(mapConfigError),
125
+ Effect.as({ name: input.name, removed: true as const }),
126
+ ),
68
127
  status,
69
128
  issueWebSocketTicket,
70
129
  };
71
130
  });
72
131
 
73
132
  export const T3AuthLive = Layer.effect(T3Auth, makeT3Auth());
133
+
134
+ function toAuthResolvedConfig(config: ResolvedConfig): AuthResolvedConfig {
135
+ return {
136
+ url: config.url,
137
+ token: config.token,
138
+ source: config.source,
139
+ local: config.local,
140
+ ...(config.environment !== undefined ? { environment: config.environment } : {}),
141
+ };
142
+ }
143
+
144
+ function toAuthEnvironmentListItem(
145
+ environment: EnvironmentSummary,
146
+ activeName: string | undefined,
147
+ ): AuthEnvironmentListItem {
148
+ return {
149
+ name: environment.name,
150
+ url: environment.url,
151
+ local: environment.local,
152
+ default: environment.default,
153
+ active: environment.name === activeName,
154
+ };
155
+ }
@@ -1,17 +1,24 @@
1
1
  import * as Effect from "effect/Effect";
2
+ import * as Option from "effect/Option";
2
3
 
3
- import { Environment } from "../environment/service.ts";
4
- import { resolveT3BaseDir } from "../layout/base-dir.ts";
4
+ import type { CliRuntime } from "../cli/runtime/service.ts";
5
+ import type { T3CliEnvShape } from "../config/env/env.ts";
6
+ import { resolveT3BaseDir } from "../config/env/layout.ts";
5
7
 
6
8
  export const resolveLocalBaseDir = Effect.fn("resolveLocalBaseDir")(function* (input: {
7
9
  readonly baseDir?: string | undefined;
10
+ readonly cliRuntime: CliRuntime["Service"];
11
+ readonly t3CliEnv: T3CliEnvShape;
8
12
  }) {
9
- const environment = yield* Environment;
13
+ const homeDir = yield* Option.match(input.t3CliEnv.home, {
14
+ onNone: () => Effect.die("HOME is not set"),
15
+ onSome: Effect.succeed,
16
+ });
10
17
  return yield* resolveT3BaseDir({
11
18
  layout: {
12
- cwd: environment.cwd,
13
- homeDir: environment.homeDir,
14
- t3codeHome: environment.env["T3CODE_HOME"],
19
+ cwd: input.cliRuntime.cwd,
20
+ homeDir,
21
+ t3codeHome: Option.getOrUndefined(input.t3CliEnv.t3codeHome),
15
22
  },
16
23
  baseDir: input.baseDir,
17
24
  });
@@ -4,8 +4,9 @@ import * as FileSystem from "effect/FileSystem";
4
4
  import * as Layer from "effect/Layer";
5
5
  import * as Path from "effect/Path";
6
6
 
7
- import { normalizeHttpBaseUrl } from "../config/url.ts";
8
- import { Environment } from "../environment/service.ts";
7
+ import { normalizeHttpBaseUrl } from "../config/url/url.ts";
8
+ import { loadT3CliEnv } from "../config/env/env.ts";
9
+ import { CliRuntime } from "../cli/runtime/service.ts";
9
10
  import { AuthLocalError } from "./error.ts";
10
11
  import { resolveLocalBaseDir } from "./local-base-dir.ts";
11
12
  import { decodeAuthLocalRuntimeStateFromJson } from "./schema.ts";
@@ -21,15 +22,17 @@ export class T3LocalAuthOrigin extends Context.Service<
21
22
  export const makeT3LocalAuthOrigin = Effect.fn("makeT3LocalAuthOrigin")(function* () {
22
23
  const fs = yield* FileSystem.FileSystem;
23
24
  const path = yield* Path.Path;
24
- const environment = yield* Environment;
25
+ const cliRuntime = yield* CliRuntime;
26
+ const t3CliEnv = yield* loadT3CliEnv;
25
27
 
26
28
  const resolve = Effect.fn("T3LocalAuthOriginLive.resolve")(function* (
27
29
  input?: LocalAuthOriginInput,
28
30
  ) {
29
- const baseDir = yield* resolveLocalBaseDir({ baseDir: input?.baseDir }).pipe(
30
- Effect.provideService(Environment, environment),
31
- Effect.provideService(Path.Path, path),
32
- );
31
+ const baseDir = yield* resolveLocalBaseDir({
32
+ baseDir: input?.baseDir,
33
+ cliRuntime,
34
+ t3CliEnv,
35
+ }).pipe(Effect.provideService(Path.Path, path));
33
36
  if (input?.origin !== undefined) {
34
37
  return yield* normalizeLocalOrigin(input.origin);
35
38
  }
@@ -2,7 +2,7 @@ import {
2
2
  AuthAdministrativeScopes,
3
3
  AuthSessionId,
4
4
  type AuthEnvironmentScope,
5
- } from "#t3tools/contracts";
5
+ } from "@t3tools/contracts";
6
6
  import * as Context from "effect/Context";
7
7
  import * as Crypto from "effect/Crypto";
8
8
  import * as DateTime from "effect/DateTime";
@@ -15,7 +15,8 @@ import * as Path from "effect/Path";
15
15
  import * as Predicate from "effect/Predicate";
16
16
  import * as SqlClient from "effect/unstable/sql/SqlClient";
17
17
 
18
- import { Environment } from "../environment/service.ts";
18
+ import { loadT3CliEnv } from "../config/env/env.ts";
19
+ import { CliRuntime } from "../cli/runtime/service.ts";
19
20
  import { SqlClientFactory } from "../sql/service.ts";
20
21
  import {
21
22
  AuthLocalDatabaseError,
@@ -38,7 +39,8 @@ export class T3LocalAuthToken extends Context.Service<
38
39
  export const makeT3LocalAuthToken = Effect.fn("makeT3LocalAuthToken")(function* () {
39
40
  const fs = yield* FileSystem.FileSystem;
40
41
  const path = yield* Path.Path;
41
- const environment = yield* Environment;
42
+ const cliRuntime = yield* CliRuntime;
43
+ const t3CliEnv = yield* loadT3CliEnv;
42
44
  const crypto = yield* Crypto.Crypto;
43
45
  const sqlClientFactory = yield* SqlClientFactory;
44
46
 
@@ -100,14 +102,15 @@ export const makeT3LocalAuthToken = Effect.fn("makeT3LocalAuthToken")(function*
100
102
 
101
103
  function openAuthDatabase(dbPath: string) {
102
104
  return sqlClientFactory.sqliteClient({ filename: dbPath }).pipe(
103
- Effect.catchTag("SqlError", (error) =>
104
- Effect.fail(
105
- new AuthLocalDatabaseError({
106
- operation: "connect",
107
- message: error.message,
108
- }),
109
- ),
110
- ),
105
+ Effect.catchTags({
106
+ SqlError: (error) =>
107
+ Effect.fail(
108
+ new AuthLocalDatabaseError({
109
+ operation: "connect",
110
+ message: error.message,
111
+ }),
112
+ ),
113
+ }),
111
114
  );
112
115
  }
113
116
 
@@ -157,14 +160,15 @@ export const makeT3LocalAuthToken = Effect.fn("makeT3LocalAuthToken")(function*
157
160
  expiresAt: DateTime.formatIso(expiresAt),
158
161
  }).pipe(
159
162
  provideAuthDatabase(input.dbPath),
160
- Effect.catchTag("SqlError", (error) =>
161
- Effect.fail(
162
- new AuthLocalDatabaseError({
163
- operation: Predicate.isTagged(error.reason, "ConnectionError") ? "connect" : "query",
164
- message: error.message,
165
- }),
166
- ),
167
- ),
163
+ Effect.catchTags({
164
+ SqlError: (error) =>
165
+ Effect.fail(
166
+ new AuthLocalDatabaseError({
167
+ operation: Predicate.isTagged(error.reason, "ConnectionError") ? "connect" : "query",
168
+ message: error.message,
169
+ }),
170
+ ),
171
+ }),
168
172
  );
169
173
  return {
170
174
  token,
@@ -185,10 +189,11 @@ export const makeT3LocalAuthToken = Effect.fn("makeT3LocalAuthToken")(function*
185
189
  );
186
190
  }
187
191
 
188
- const baseDir = yield* resolveLocalBaseDir({ baseDir: input.baseDir }).pipe(
189
- Effect.provideService(Environment, environment),
190
- Effect.provideService(Path.Path, path),
191
- );
192
+ const baseDir = yield* resolveLocalBaseDir({
193
+ baseDir: input.baseDir,
194
+ cliRuntime,
195
+ t3CliEnv,
196
+ }).pipe(Effect.provideService(Path.Path, path));
192
197
  const session = yield* issueLocalDatabaseSession({
193
198
  dbPath: path.join(baseDir, "userdata", "state.sqlite"),
194
199
  secretsDir: path.join(baseDir, "userdata", "secrets"),
@@ -0,0 +1,200 @@
1
+ import "vite-plus/test/config";
2
+
3
+ import * as Effect from "effect/Effect";
4
+ import * as Exit from "effect/Exit";
5
+ import * as FileSystem from "effect/FileSystem";
6
+ import * as Path from "effect/Path";
7
+ import * as Schema from "effect/Schema";
8
+ import { assert, describe, it } from "@effect/vitest";
9
+
10
+ import { T3Auth } from "./service.ts";
11
+ import { StoredConfigV2FileJson } from "../config/persist/schema.ts";
12
+ import { ConfigPlatformLayer } from "../config/platform.test-utils.ts";
13
+ import { makeTempHomeScoped } from "../config/temp-home.test-utils.ts";
14
+ import { t3AuthDepsLayer } from "./layer.test-utils.ts";
15
+
16
+ describe("T3Auth persistence", () => {
17
+ it.effect("fails to persist a duplicate environment without allowReplace", () =>
18
+ Effect.gen(function* () {
19
+ return yield* makeTempHomeScoped("t3cli-auth-");
20
+ }).pipe(
21
+ Effect.flatMap((homeDir) =>
22
+ Effect.gen(function* () {
23
+ const auth = yield* T3Auth;
24
+ yield* auth.persistEnvironment({
25
+ name: "work",
26
+ url: "https://work.example",
27
+ token: "work-token",
28
+ local: false,
29
+ allowReplace: true,
30
+ });
31
+ const result = yield* auth
32
+ .persistEnvironment({
33
+ name: "work",
34
+ url: "https://work.example",
35
+ token: "work-token-2",
36
+ local: false,
37
+ allowReplace: false,
38
+ })
39
+ .pipe(Effect.exit);
40
+ assert.equal(Exit.isFailure(result), true);
41
+ }).pipe(Effect.provide(t3AuthDepsLayer(homeDir))),
42
+ ),
43
+ Effect.provide(ConfigPlatformLayer),
44
+ Effect.scoped,
45
+ ),
46
+ );
47
+
48
+ it.effect("does not change default when replace is used for a new environment", () =>
49
+ Effect.gen(function* () {
50
+ return yield* makeTempHomeScoped("t3cli-auth-");
51
+ }).pipe(
52
+ Effect.flatMap((homeDir) =>
53
+ Effect.gen(function* () {
54
+ const auth = yield* T3Auth;
55
+ yield* auth.persistEnvironment({
56
+ name: "home",
57
+ url: "https://home.example",
58
+ token: "home-token",
59
+ local: false,
60
+ allowReplace: true,
61
+ });
62
+ yield* auth.persistEnvironment({
63
+ name: "work",
64
+ url: "https://work.example",
65
+ token: "work-token",
66
+ local: false,
67
+ replace: true,
68
+ allowReplace: true,
69
+ });
70
+ const listed = yield* auth.listEnvironments();
71
+ assert.equal(listed.find((environment) => environment.name === "home")?.default, true);
72
+ assert.equal(listed.find((environment) => environment.name === "work")?.default, false);
73
+ }).pipe(Effect.provide(t3AuthDepsLayer(homeDir))),
74
+ ),
75
+ Effect.provide(ConfigPlatformLayer),
76
+ Effect.scoped,
77
+ ),
78
+ );
79
+
80
+ it.effect("promotes default when replacing an existing environment with replace", () =>
81
+ Effect.gen(function* () {
82
+ return yield* makeTempHomeScoped("t3cli-auth-");
83
+ }).pipe(
84
+ Effect.flatMap((homeDir) =>
85
+ Effect.gen(function* () {
86
+ const auth = yield* T3Auth;
87
+ yield* auth.persistEnvironment({
88
+ name: "home",
89
+ url: "https://home.example",
90
+ token: "home-token",
91
+ local: false,
92
+ allowReplace: true,
93
+ });
94
+ yield* auth.persistEnvironment({
95
+ name: "work",
96
+ url: "https://work.example",
97
+ token: "work-token",
98
+ local: false,
99
+ allowReplace: true,
100
+ });
101
+ yield* auth.persistEnvironment({
102
+ name: "work",
103
+ url: "https://work.example",
104
+ token: "work-token-2",
105
+ local: false,
106
+ replace: true,
107
+ allowReplace: true,
108
+ });
109
+ const listed = yield* auth.listEnvironments();
110
+ assert.equal(listed.find((environment) => environment.name === "work")?.default, true);
111
+ }).pipe(Effect.provide(t3AuthDepsLayer(homeDir))),
112
+ ),
113
+ Effect.provide(ConfigPlatformLayer),
114
+ Effect.scoped,
115
+ ),
116
+ );
117
+
118
+ it.effect("lists environments without decrypting tokens", () =>
119
+ Effect.gen(function* () {
120
+ return yield* makeTempHomeScoped("t3cli-auth-");
121
+ }).pipe(
122
+ Effect.flatMap((homeDir) =>
123
+ Effect.gen(function* () {
124
+ const fs = yield* FileSystem.FileSystem;
125
+ const path = yield* Path.Path;
126
+ const configPath = path.join(homeDir, ".config", "t3cli", "config.json");
127
+
128
+ yield* Effect.gen(function* () {
129
+ const auth = yield* T3Auth;
130
+ yield* auth.persistEnvironment({
131
+ name: "home",
132
+ url: "https://home.example",
133
+ token: "home-token",
134
+ local: false,
135
+ allowReplace: true,
136
+ });
137
+ yield* auth.persistEnvironment({
138
+ name: "work",
139
+ url: "https://work.example",
140
+ token: "work-token",
141
+ local: false,
142
+ allowReplace: true,
143
+ });
144
+ }).pipe(Effect.provide(t3AuthDepsLayer(homeDir)));
145
+
146
+ const raw = yield* fs.readFileString(configPath);
147
+ const parsed = yield* Schema.decodeUnknownEffect(StoredConfigV2FileJson)(raw);
148
+ const homeEnvironment = parsed.environments.home;
149
+ assert.isDefined(homeEnvironment);
150
+ const corrupted = yield* Schema.encodeEffect(StoredConfigV2FileJson)({
151
+ ...parsed,
152
+ environments: {
153
+ ...parsed.environments,
154
+ home: {
155
+ ...homeEnvironment,
156
+ token: {
157
+ ...homeEnvironment.token,
158
+ tag: "AAAAAAAAAAAAAAAAAAAAAA==",
159
+ },
160
+ },
161
+ },
162
+ });
163
+ yield* fs.writeFileString(configPath, `${corrupted}\n`, { mode: 0o600 });
164
+
165
+ yield* Effect.gen(function* () {
166
+ const auth = yield* T3Auth;
167
+ const listed = yield* auth.listEnvironments();
168
+ assert.equal(listed.length, 2);
169
+ assert.equal(listed.find((environment) => environment.name === "home")?.active, true);
170
+ }).pipe(Effect.provide(t3AuthDepsLayer(homeDir)));
171
+ }),
172
+ ),
173
+ Effect.provide(ConfigPlatformLayer),
174
+ Effect.scoped,
175
+ ),
176
+ );
177
+
178
+ it.effect("resolves unpair target from encrypted default metadata", () =>
179
+ Effect.gen(function* () {
180
+ return yield* makeTempHomeScoped("t3cli-auth-");
181
+ }).pipe(
182
+ Effect.flatMap((homeDir) =>
183
+ Effect.gen(function* () {
184
+ const auth = yield* T3Auth;
185
+ yield* auth.persistEnvironment({
186
+ name: "home",
187
+ url: "https://home.example",
188
+ token: "home-token",
189
+ local: false,
190
+ allowReplace: true,
191
+ });
192
+ const target = yield* auth.resolveUnpairTarget({});
193
+ assert.equal(target, "home");
194
+ }).pipe(Effect.provide(t3AuthDepsLayer(homeDir))),
195
+ ),
196
+ Effect.provide(ConfigPlatformLayer),
197
+ Effect.scoped,
198
+ ),
199
+ );
200
+ });
@@ -1,9 +1,19 @@
1
1
  import * as Context from "effect/Context";
2
2
  import type * as Effect from "effect/Effect";
3
3
 
4
- import type { AuthSessionState, AuthWebSocketTicketResult } from "./schema.ts";
4
+ import type { AuthWebSocketTicketResult } from "./schema.ts";
5
5
  import type { AuthError } from "./error.ts";
6
- import type { AuthConfigInput, LocalAuthInput, LocalAuthResult, PairResult } from "./type.ts";
6
+ import type {
7
+ AuthConfigInput,
8
+ AuthEnvironmentListItem,
9
+ AuthStatusResult,
10
+ AuthUnpairResult,
11
+ AuthUseResult,
12
+ LocalAuthInput,
13
+ LocalAuthResult,
14
+ PairResult,
15
+ PersistEnvironmentInput,
16
+ } from "./type.ts";
7
17
 
8
18
  export class T3Auth extends Context.Service<
9
19
  T3Auth,
@@ -11,7 +21,21 @@ export class T3Auth extends Context.Service<
11
21
  readonly pair: (value: string) => Effect.Effect<PairResult, AuthError>;
12
22
  readonly local: (input: LocalAuthInput) => Effect.Effect<LocalAuthResult, AuthError>;
13
23
  readonly writeConfig: (input: AuthConfigInput) => Effect.Effect<void, AuthError>;
14
- readonly status: () => Effect.Effect<AuthSessionState, AuthError>;
24
+ readonly persistEnvironment: (
25
+ input: PersistEnvironmentInput,
26
+ ) => Effect.Effect<string, AuthError>;
27
+ readonly environmentExists: (name: string) => Effect.Effect<boolean, AuthError>;
28
+ readonly defaultNameFromUrl: (url: string) => Effect.Effect<string, AuthError>;
29
+ readonly defaultNameForLocal: () => Effect.Effect<string, AuthError>;
30
+ readonly listEnvironments: () => Effect.Effect<readonly AuthEnvironmentListItem[], AuthError>;
31
+ readonly useEnvironment: (name: string) => Effect.Effect<AuthUseResult, AuthError>;
32
+ readonly unpairEnvironment: (input: {
33
+ readonly name: string;
34
+ }) => Effect.Effect<AuthUnpairResult, AuthError>;
35
+ readonly resolveUnpairTarget: (input: {
36
+ readonly name?: string;
37
+ }) => Effect.Effect<string, AuthError>;
38
+ readonly status: () => Effect.Effect<AuthStatusResult, AuthError>;
15
39
  readonly issueWebSocketTicket: () => Effect.Effect<AuthWebSocketTicketResult, AuthError>;
16
40
  }
17
41
  >()("t3cli/T3Auth") {}
@@ -2,14 +2,14 @@ import {
2
2
  AuthAccessTokenType,
3
3
  AuthEnvironmentBootstrapTokenType,
4
4
  AuthTokenExchangeGrantType,
5
- } from "#t3tools/contracts";
5
+ } from "@t3tools/contracts";
6
6
  import * as Context from "effect/Context";
7
7
  import * as DateTime from "effect/DateTime";
8
8
  import * as Effect from "effect/Effect";
9
9
  import * as Layer from "effect/Layer";
10
10
  import { HttpClient, HttpClientError, HttpClientRequest } from "effect/unstable/http";
11
11
 
12
- import { toHttpEndpointUrl } from "../config/url.ts";
12
+ import { toHttpEndpointUrl } from "../config/url/url.ts";
13
13
  import { AuthTransportError } from "./error.ts";
14
14
  import {
15
15
  type AuthBearerBootstrapResult,
package/src/auth/type.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { AuthBearerBootstrapResult } from "./schema.ts";
2
+ import type { AuthSessionState } from "./schema.ts";
2
3
 
3
4
  export type AuthSessionRole = AuthBearerBootstrapResult["role"];
4
5
 
@@ -8,9 +9,44 @@ export type PairingUrl = {
8
9
  };
9
10
 
10
11
  export type AuthConfigInput = {
12
+ readonly name: string;
11
13
  readonly url: string;
12
14
  readonly token: string;
13
- readonly local?: boolean;
15
+ readonly local: boolean;
16
+ readonly makeDefault?: boolean;
17
+ };
18
+
19
+ export type PersistEnvironmentInput = {
20
+ readonly name: string;
21
+ readonly url: string;
22
+ readonly token: string;
23
+ readonly local: boolean;
24
+ readonly replace?: boolean;
25
+ readonly allowReplace: boolean;
26
+ };
27
+
28
+ export type AuthResolvedConfig = {
29
+ readonly url: string;
30
+ readonly token: string;
31
+ readonly source: "env" | "config";
32
+ readonly local: boolean;
33
+ readonly environment?: string;
34
+ };
35
+
36
+ export type AuthEnvironmentSummary = {
37
+ readonly name: string;
38
+ readonly url: string;
39
+ readonly local: boolean;
40
+ readonly default: boolean;
41
+ };
42
+
43
+ export type AuthStatusResult = {
44
+ readonly config: AuthResolvedConfig;
45
+ readonly session: AuthSessionState;
46
+ };
47
+
48
+ export type AuthEnvironmentListItem = AuthEnvironmentSummary & {
49
+ readonly active: boolean;
14
50
  };
15
51
 
16
52
  export type PairResult = {
@@ -51,3 +87,13 @@ export type LocalAuthResult = {
51
87
  readonly source: "local";
52
88
  readonly baseDir: string;
53
89
  };
90
+
91
+ export type AuthUseResult = {
92
+ readonly name: string;
93
+ readonly default: true;
94
+ };
95
+
96
+ export type AuthUnpairResult = {
97
+ readonly name: string;
98
+ readonly removed: true;
99
+ };