@dxos/cli-util 0.11.1 → 0.12.0-next-73daef452f1464b62efdbca75fb0067c1066f264

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 (87) hide show
  1. package/dist/lib/callback.mjs +2 -0
  2. package/dist/lib/chunk-command-config.mjs +2 -2
  3. package/dist/lib/chunk-command-config.mjs.map +1 -1
  4. package/dist/lib/chunk-server.mjs +112 -0
  5. package/dist/lib/chunk-server.mjs.map +1 -0
  6. package/dist/lib/index.mjs +181 -258
  7. package/dist/lib/index.mjs.map +1 -1
  8. package/dist/lib/oauth.mjs +77 -0
  9. package/dist/lib/oauth.mjs.map +1 -0
  10. package/dist/lib/platform.browser.mjs +25 -0
  11. package/dist/lib/platform.browser.mjs.map +1 -0
  12. package/dist/lib/platform.node.mjs +88 -0
  13. package/dist/lib/platform.node.mjs.map +1 -0
  14. package/dist/lib/testing.mjs +6 -6
  15. package/dist/lib/testing.mjs.map +1 -1
  16. package/dist/lib/util/platform.browser.mjs +2 -0
  17. package/dist/lib/util/platform.node.mjs +2 -0
  18. package/dist/types/src/callback/index.d.ts +2 -0
  19. package/dist/types/src/callback/index.d.ts.map +1 -0
  20. package/dist/types/src/callback/server.d.ts +34 -0
  21. package/dist/types/src/callback/server.d.ts.map +1 -0
  22. package/dist/types/src/index.d.ts +0 -1
  23. package/dist/types/src/index.d.ts.map +1 -1
  24. package/dist/types/src/oauth/index.d.ts +0 -1
  25. package/dist/types/src/oauth/index.d.ts.map +1 -1
  26. package/dist/types/src/oauth/recovery.d.ts +59 -10
  27. package/dist/types/src/oauth/recovery.d.ts.map +1 -1
  28. package/dist/types/src/services/command-config.d.ts +1 -1
  29. package/dist/types/src/services/command-config.d.ts.map +1 -1
  30. package/dist/types/src/services/command-services.d.ts +18 -0
  31. package/dist/types/src/services/command-services.d.ts.map +1 -0
  32. package/dist/types/src/services/index.d.ts +1 -0
  33. package/dist/types/src/services/index.d.ts.map +1 -1
  34. package/dist/types/src/testing/test-console.d.ts +1 -1
  35. package/dist/types/src/testing/test-console.d.ts.map +1 -1
  36. package/dist/types/src/testing/test-layer.d.ts +1 -1
  37. package/dist/types/src/testing/test-layer.d.ts.map +1 -1
  38. package/dist/types/src/util/Ansi.d.ts +23 -0
  39. package/dist/types/src/util/Ansi.d.ts.map +1 -0
  40. package/dist/types/src/util/Doc.d.ts +51 -0
  41. package/dist/types/src/util/Doc.d.ts.map +1 -0
  42. package/dist/types/src/util/form-builder.d.ts +2 -2
  43. package/dist/types/src/util/form-builder.d.ts.map +1 -1
  44. package/dist/types/src/util/index.d.ts +3 -1
  45. package/dist/types/src/util/index.d.ts.map +1 -1
  46. package/dist/types/src/util/options.d.ts +5 -4
  47. package/dist/types/src/util/options.d.ts.map +1 -1
  48. package/dist/types/src/util/platform.browser.d.ts +13 -0
  49. package/dist/types/src/util/platform.browser.d.ts.map +1 -0
  50. package/dist/types/src/util/{platform.d.ts → platform.node.d.ts} +1 -1
  51. package/dist/types/src/util/platform.node.d.ts.map +1 -0
  52. package/dist/types/src/util/printer.d.ts +1 -1
  53. package/dist/types/src/util/printer.d.ts.map +1 -1
  54. package/dist/types/src/util/space-format.d.ts +1 -1
  55. package/dist/types/src/util/space-format.d.ts.map +1 -1
  56. package/dist/types/src/util/space.d.ts +14 -0
  57. package/dist/types/src/util/space.d.ts.map +1 -1
  58. package/dist/types/src/util/space.test.d.ts +2 -0
  59. package/dist/types/src/util/space.test.d.ts.map +1 -0
  60. package/dist/types/src/util/timeout.d.ts +2 -2
  61. package/dist/types/src/util/timeout.d.ts.map +1 -1
  62. package/dist/types/tsconfig.tsbuildinfo +1 -1
  63. package/package.json +38 -22
  64. package/src/callback/index.ts +5 -0
  65. package/src/{oauth → callback}/server.ts +63 -40
  66. package/src/index.ts +0 -1
  67. package/src/oauth/index.ts +0 -1
  68. package/src/oauth/recovery.ts +66 -25
  69. package/src/services/command-config.ts +2 -2
  70. package/src/services/command-services.ts +22 -0
  71. package/src/services/index.ts +1 -0
  72. package/src/testing/test-console.ts +7 -5
  73. package/src/util/Ansi.ts +36 -0
  74. package/src/util/Doc.ts +102 -0
  75. package/src/util/form-builder.ts +3 -2
  76. package/src/util/index.ts +4 -1
  77. package/src/util/options.ts +3 -3
  78. package/src/util/platform.browser.ts +31 -0
  79. package/src/util/{platform.ts → platform.node.ts} +28 -20
  80. package/src/util/printer.ts +3 -4
  81. package/src/util/space-format.ts +7 -7
  82. package/src/util/space.test.ts +31 -0
  83. package/src/util/space.ts +77 -21
  84. package/src/util/timeout.ts +3 -3
  85. package/dist/types/src/oauth/server.d.ts +0 -28
  86. package/dist/types/src/oauth/server.d.ts.map +0 -1
  87. package/dist/types/src/util/platform.d.ts.map +0 -1
@@ -0,0 +1,2 @@
1
+ import { n as startLocalCallbackServer, t as CALLBACK_TIMEOUT_MS } from "./chunk-server.mjs";
2
+ export { CALLBACK_TIMEOUT_MS, startLocalCallbackServer };
@@ -1,8 +1,8 @@
1
1
  import * as Effect from "effect/Effect";
2
- import * as Layer from "effect/Layer";
3
2
  import * as Context from "effect/Context";
3
+ import * as Layer from "effect/Layer";
4
4
  //#region src/services/command-config.ts
5
- var CommandConfig = class CommandConfig extends Context.Tag("CommandConfig")() {
5
+ var CommandConfig = class CommandConfig extends Context.Service()("CommandConfig") {
6
6
  static isJson = CommandConfig.pipe(Effect.map((config) => config.json));
7
7
  static isVerbose = CommandConfig.pipe(Effect.map((config) => config.verbose));
8
8
  static layerTest = Layer.succeed(CommandConfig, {
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-command-config.mjs","names":[],"sources":["../../src/services/command-config.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\n\nexport class CommandConfig extends Context.Tag('CommandConfig')<\n CommandConfig,\n {\n json: boolean;\n verbose: boolean;\n profile: string;\n logLevel: string;\n }\n>() {\n static isJson: Effect.Effect<boolean, never, CommandConfig> = CommandConfig.pipe(Effect.map((config) => config.json));\n static isVerbose: Effect.Effect<boolean, never, CommandConfig> = CommandConfig.pipe(\n Effect.map((config) => config.verbose),\n );\n\n static layerTest = Layer.succeed(CommandConfig, {\n json: true,\n verbose: false,\n profile: 'default',\n logLevel: 'info',\n });\n}\n"],"mappings":";;;;AAQA,IAAa,gBAAb,MAAa,sBAAsB,QAAQ,IAAI,eAAe,CAAC,CAQ7D,CAAC,CAAC;CACF,OAAO,SAAuD,cAAc,KAAK,OAAO,KAAK,WAAW,OAAO,IAAI,CAAC;CACpH,OAAO,YAA0D,cAAc,KAC7E,OAAO,KAAK,WAAW,OAAO,OAAO,CACvC;CAEA,OAAO,YAAY,MAAM,QAAQ,eAAe;EAC9C,MAAM;EACN,SAAS;EACT,SAAS;EACT,UAAU;CACZ,CAAC;AACH"}
1
+ {"version":3,"file":"chunk-command-config.mjs","names":[],"sources":["../../src/services/command-config.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\n\nexport class CommandConfig extends Context.Service<\n CommandConfig,\n {\n json: boolean;\n verbose: boolean;\n profile: string;\n logLevel: string;\n }\n>()('CommandConfig') {\n static isJson: Effect.Effect<boolean, never, CommandConfig> = CommandConfig.pipe(Effect.map((config) => config.json));\n static isVerbose: Effect.Effect<boolean, never, CommandConfig> = CommandConfig.pipe(\n Effect.map((config) => config.verbose),\n );\n\n static layerTest = Layer.succeed(CommandConfig, {\n json: true,\n verbose: false,\n profile: 'default',\n logLevel: 'info',\n });\n}\n"],"mappings":";;;;AAQA,IAAa,gBAAb,MAAa,sBAAsB,QAAQ,QAQzC,CAAC,CAAC,eAAe,CAAC,CAAC;CACnB,OAAO,SAAuD,cAAc,KAAK,OAAO,KAAK,WAAW,OAAO,IAAI,CAAC;CACpH,OAAO,YAA0D,cAAc,KAC7E,OAAO,KAAK,WAAW,OAAO,OAAO,CACvC;CAEA,OAAO,YAAY,MAAM,QAAQ,eAAe;EAC9C,MAAM;EACN,SAAS;EACT,SAAS;EACT,UAAU;CACZ,CAAC;AACH"}
@@ -0,0 +1,112 @@
1
+ import { t as CommandConfig } from "./chunk-command-config.mjs";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Layer from "effect/Layer";
4
+ import { openBrowser } from "#platform";
5
+ import * as Option from "effect/Option";
6
+ import * as BunHttpServer from "@effect/platform-bun/BunHttpServer";
7
+ import * as Exit from "effect/Exit";
8
+ import * as Ref from "effect/Ref";
9
+ import * as Scope from "effect/Scope";
10
+ import * as HttpRouter from "effect/unstable/http/HttpRouter";
11
+ import * as HttpServerRequest from "effect/unstable/http/HttpServerRequest";
12
+ import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse";
13
+ import { getPort } from "get-port-please";
14
+ //#region src/callback/server.ts
15
+ /** Default timeout for a full browser round-trip. */
16
+ var CALLBACK_TIMEOUT_MS = 3e5;
17
+ /**
18
+ * Relay page that performs a top-level redirect to Edge's `authUrl`. Edge finalizes the flow
19
+ * by redirecting the browser back to this server's callback path (bsky.social nullifies
20
+ * `window.opener`, so a popup + postMessage relay can't be used).
21
+ */
22
+ var getRelayPageHtml = (authUrl) => `
23
+ <!DOCTYPE html>
24
+ <html>
25
+ <head>
26
+ <meta charset="UTF-8">
27
+ <script>
28
+ window.location.href = '${authUrl.replace(/'/g, "\\'")}';
29
+ <\/script>
30
+ </head>
31
+ <body></body>
32
+ </html>
33
+ `;
34
+ /**
35
+ * Starts a local Bun HTTP server that captures a browser redirect back to `callbackPath`. Generic
36
+ * over the callback shape: all query params are captured and returned; an `error` query param
37
+ * fails the wait. `open` additionally relays the browser to a remote auth URL, for flows that
38
+ * start from the CLI rather than from a link the user clicks.
39
+ *
40
+ * Used by the integration-connect flow (`/redirect/oauth`), the identity-recovery login flow
41
+ * (`/redirect/oauth-recovery`), and the email login link, which lands on `/` after the hub's
42
+ * activation route redirects.
43
+ */
44
+ var startLocalCallbackServer = (callbackPath, { successMessage = "Authentication successful! You can close this window." } = {}) => Effect.gen(function* () {
45
+ const port = yield* Effect.promise(() => getPort({ random: true }));
46
+ const origin = `http://localhost:${port}`;
47
+ const received = yield* Ref.make(false);
48
+ const outcome = yield* Ref.make(Option.none());
49
+ const parseUrl = (rawUrl) => new URL(rawUrl.startsWith("http") ? rawUrl : `http://localhost${rawUrl}`);
50
+ const routes = HttpRouter.addAll([HttpRouter.route("GET", "/oauth-relay", Effect.gen(function* () {
51
+ const request = yield* HttpServerRequest.HttpServerRequest;
52
+ const authUrl = parseUrl(request.url).searchParams.get("authUrl");
53
+ if (!authUrl) return HttpServerResponse.text("Missing authUrl parameter", { status: 400 });
54
+ return HttpServerResponse.text(getRelayPageHtml(authUrl), { headers: { "Content-Type": "text/html" } });
55
+ })), HttpRouter.route("GET", callbackPath, Effect.gen(function* () {
56
+ if (Option.isSome(yield* Ref.get(outcome))) return HttpServerResponse.text("Already received.", { status: 400 });
57
+ const request = yield* HttpServerRequest.HttpServerRequest;
58
+ const params = parseUrl(request.url).searchParams;
59
+ const error = params.get("error");
60
+ if (error) {
61
+ yield* Ref.set(outcome, Option.some({
62
+ success: false,
63
+ reason: error
64
+ }));
65
+ yield* Ref.set(received, true);
66
+ return HttpServerResponse.text(`<html><body><h1>Authentication failed</h1><p>${error}</p></body></html>`, {
67
+ status: 400,
68
+ headers: { "Content-Type": "text/html" }
69
+ });
70
+ }
71
+ const captured = {};
72
+ for (const [key, value] of params.entries()) captured[key] = value;
73
+ yield* Ref.set(outcome, Option.some({
74
+ success: true,
75
+ params: captured
76
+ }));
77
+ yield* Ref.set(received, true);
78
+ return HttpServerResponse.text(`<html><body><h1>${successMessage}</h1></body></html>`, { headers: { "Content-Type": "text/html" } });
79
+ }))]);
80
+ const verbose = yield* Effect.serviceOption(CommandConfig).pipe(Effect.map(Option.match({
81
+ onNone: () => false,
82
+ onSome: (config) => config.verbose
83
+ })));
84
+ const serverLayer = HttpRouter.serve(routes, {
85
+ disableLogger: !verbose,
86
+ disableListenLog: !verbose
87
+ }).pipe(Layer.provide(BunHttpServer.layer({ port })));
88
+ const scope = yield* Scope.make();
89
+ yield* Layer.build(serverLayer).pipe(Scope.provide(scope));
90
+ const waitForResult = (timeoutMs = CALLBACK_TIMEOUT_MS) => Effect.race(Effect.gen(function* () {
91
+ while (true) {
92
+ if (yield* Ref.get(received)) break;
93
+ yield* Effect.sleep("500 millis");
94
+ }
95
+ const result = yield* Ref.get(outcome);
96
+ return yield* Option.match(result, {
97
+ onNone: () => Effect.fail(/* @__PURE__ */ new Error("Callback received but no result.")),
98
+ onSome: (value) => value.success ? Effect.succeed(value.params) : Effect.fail(/* @__PURE__ */ new Error(`Callback reported a failure: ${value.reason}`))
99
+ });
100
+ }), Effect.sleep(`${timeoutMs} millis`).pipe(Effect.flatMap(() => Effect.fail(/* @__PURE__ */ new Error("Timed out waiting for the browser callback.")))));
101
+ return {
102
+ port,
103
+ origin,
104
+ open: (authUrl) => openBrowser(`${origin}/oauth-relay?authUrl=${encodeURIComponent(authUrl)}`),
105
+ waitForResult,
106
+ stop: () => Scope.close(scope, Exit.void).pipe(Effect.catch(() => Effect.void))
107
+ };
108
+ });
109
+ //#endregion
110
+ export { startLocalCallbackServer as n, CALLBACK_TIMEOUT_MS as t };
111
+
112
+ //# sourceMappingURL=chunk-server.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-server.mjs","names":[],"sources":["../../src/callback/server.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as BunHttpServer from '@effect/platform-bun/BunHttpServer';\nimport * as Effect from 'effect/Effect';\nimport * as Exit from 'effect/Exit';\nimport * as Layer from 'effect/Layer';\nimport * as Option from 'effect/Option';\nimport * as Ref from 'effect/Ref';\nimport * as Scope from 'effect/Scope';\nimport * as HttpRouter from 'effect/unstable/http/HttpRouter';\nimport * as HttpServerRequest from 'effect/unstable/http/HttpServerRequest';\nimport * as HttpServerResponse from 'effect/unstable/http/HttpServerResponse';\nimport { getPort } from 'get-port-please';\n\nimport { openBrowser } from '#platform';\n\nimport { CommandConfig } from '../services';\n\n/** Default timeout for a full browser round-trip. */\nexport const CALLBACK_TIMEOUT_MS = 5 * 60 * 1000;\n\n/**\n * Relay page that performs a top-level redirect to Edge's `authUrl`. Edge finalizes the flow\n * by redirecting the browser back to this server's callback path (bsky.social nullifies\n * `window.opener`, so a popup + postMessage relay can't be used).\n */\nconst getRelayPageHtml = (authUrl: string) => `\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"UTF-8\">\n <script>\n window.location.href = '${authUrl.replace(/'/g, \"\\\\'\")}';\n </script>\n</head>\n<body></body>\n</html>\n`;\n\ntype CallbackOutcome = { success: true; params: Record<string, string> } | { success: false; reason: string };\n\n/**\n * A running local callback server.\n */\nexport type LocalCallbackServer = {\n /** Port the server is listening on. */\n readonly port: number;\n /** Origin (e.g. `http://localhost:1234`) to advertise as the redirect target. */\n readonly origin: string;\n /** Opens `authUrl` in the browser via the local relay page. */\n readonly open: (authUrl: string) => Effect.Effect<void, Error>;\n /** Resolves with the captured callback query params, or fails on an `error` param / timeout. */\n readonly waitForResult: (timeoutMs?: number) => Effect.Effect<Record<string, string>, Error>;\n /** Stops the server. */\n readonly stop: () => Effect.Effect<void>;\n};\n\nexport type LocalCallbackServerOptions = {\n /** Heading shown on the page the browser lands on. Defaults to an authentication wording. */\n readonly successMessage?: string;\n};\n\n/**\n * Starts a local Bun HTTP server that captures a browser redirect back to `callbackPath`. Generic\n * over the callback shape: all query params are captured and returned; an `error` query param\n * fails the wait. `open` additionally relays the browser to a remote auth URL, for flows that\n * start from the CLI rather than from a link the user clicks.\n *\n * Used by the integration-connect flow (`/redirect/oauth`), the identity-recovery login flow\n * (`/redirect/oauth-recovery`), and the email login link, which lands on `/` after the hub's\n * activation route redirects.\n */\nexport const startLocalCallbackServer = (\n callbackPath: `/${string}`,\n { successMessage = 'Authentication successful! You can close this window.' }: LocalCallbackServerOptions = {},\n): Effect.Effect<LocalCallbackServer, Error> =>\n Effect.gen(function* () {\n const port = yield* Effect.promise(() => getPort({ random: true }));\n const origin = `http://localhost:${port}`;\n const received = yield* Ref.make(false);\n const outcome = yield* Ref.make<Option.Option<CallbackOutcome>>(Option.none());\n\n // req.url is only the path + query, so reconstruct a full URL to parse the query string.\n const parseUrl = (rawUrl: string) => new URL(rawUrl.startsWith('http') ? rawUrl : `http://localhost${rawUrl}`);\n\n // v4's router is a service: routes are declared as `Route` values and installed by a layer,\n // rather than folded into an immutable router value.\n const routes = HttpRouter.addAll([\n HttpRouter.route(\n 'GET',\n '/oauth-relay',\n Effect.gen(function* () {\n const request = yield* HttpServerRequest.HttpServerRequest;\n const authUrl = parseUrl(request.url).searchParams.get('authUrl');\n if (!authUrl) {\n return HttpServerResponse.text('Missing authUrl parameter', { status: 400 });\n }\n return HttpServerResponse.text(getRelayPageHtml(authUrl), {\n headers: { 'Content-Type': 'text/html' },\n });\n }),\n ),\n HttpRouter.route(\n 'GET',\n callbackPath,\n Effect.gen(function* () {\n if (Option.isSome(yield* Ref.get(outcome))) {\n return HttpServerResponse.text('Already received.', { status: 400 });\n }\n\n const request = yield* HttpServerRequest.HttpServerRequest;\n const params = parseUrl(request.url).searchParams;\n const error = params.get('error');\n if (error) {\n yield* Ref.set(outcome, Option.some({ success: false, reason: error }));\n yield* Ref.set(received, true);\n return HttpServerResponse.text(`<html><body><h1>Authentication failed</h1><p>${error}</p></body></html>`, {\n status: 400,\n headers: { 'Content-Type': 'text/html' },\n });\n }\n\n const captured: Record<string, string> = {};\n for (const [key, value] of params.entries()) {\n captured[key] = value;\n }\n yield* Ref.set(outcome, Option.some({ success: true, params: captured }));\n yield* Ref.set(received, true);\n return HttpServerResponse.text(`<html><body><h1>${successMessage}</h1></body></html>`, {\n headers: { 'Content-Type': 'text/html' },\n });\n }),\n ),\n ]);\n\n // The flow is interactive, so the router's per-request log lines (and the listen banner) are\n // noise between the user's command and its result; keep them behind `--verbose`.\n const verbose = yield* Effect.serviceOption(CommandConfig).pipe(\n Effect.map(Option.match({ onNone: () => false, onSome: (config) => config.verbose })),\n );\n const serverLayer = HttpRouter.serve(routes, {\n disableLogger: !verbose,\n disableListenLog: !verbose,\n }).pipe(Layer.provide(BunHttpServer.layer({ port })));\n const scope = yield* Scope.make();\n yield* Layer.build(serverLayer).pipe(Scope.provide(scope));\n\n const waitForResult = (timeoutMs: number = CALLBACK_TIMEOUT_MS) =>\n Effect.race(\n Effect.gen(function* () {\n while (true) {\n if (yield* Ref.get(received)) {\n break;\n }\n yield* Effect.sleep('500 millis');\n }\n const result = yield* Ref.get(outcome);\n return yield* Option.match(result, {\n onNone: () => Effect.fail(new Error('Callback received but no result.')),\n onSome: (value) =>\n value.success\n ? Effect.succeed(value.params)\n : Effect.fail(new Error(`Callback reported a failure: ${value.reason}`)),\n });\n }),\n Effect.sleep(`${timeoutMs} millis`).pipe(\n Effect.flatMap(() => Effect.fail(new Error('Timed out waiting for the browser callback.'))),\n ),\n );\n\n return {\n port,\n origin,\n open: (authUrl: string) => openBrowser(`${origin}/oauth-relay?authUrl=${encodeURIComponent(authUrl)}`),\n waitForResult,\n stop: () => Scope.close(scope, Exit.void).pipe(Effect.catch(() => Effect.void)),\n } satisfies LocalCallbackServer;\n });\n"],"mappings":"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"}