@dxos/cli-util 0.9.0 → 0.9.1-main.c7dcc2e112

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.
@@ -4,21 +4,270 @@ import {
4
4
  __export
5
5
  } from "./chunk-N5LOOWPE.mjs";
6
6
 
7
+ // src/oauth/server.ts
8
+ import * as BunHttpServer from "@effect/platform-bun/BunHttpServer";
9
+ import * as HttpRouter from "@effect/platform/HttpRouter";
10
+ import * as HttpServer from "@effect/platform/HttpServer";
11
+ import * as HttpServerRequest from "@effect/platform/HttpServerRequest";
12
+ import * as HttpServerResponse from "@effect/platform/HttpServerResponse";
13
+ import * as Effect2 from "effect/Effect";
14
+ import * as Exit from "effect/Exit";
15
+ import * as Layer from "effect/Layer";
16
+ import * as Option from "effect/Option";
17
+ import * as Ref from "effect/Ref";
18
+ import * as Scope from "effect/Scope";
19
+ import { getPort } from "get-port-please";
20
+
21
+ // src/util/platform.ts
22
+ import * as Effect from "effect/Effect";
23
+ import { spawn } from "node:child_process";
24
+ var copyToClipboard = (text4) => Effect.tryPromise({
25
+ try: () => {
26
+ return new Promise((resolve, reject) => {
27
+ const platform = process.platform;
28
+ let command;
29
+ let args;
30
+ if (platform === "darwin") {
31
+ command = "pbcopy";
32
+ args = [];
33
+ } else if (platform === "win32") {
34
+ command = "clip";
35
+ args = [];
36
+ } else {
37
+ command = "xclip";
38
+ args = [
39
+ "-selection",
40
+ "clipboard"
41
+ ];
42
+ }
43
+ const proc = spawn(command, args);
44
+ proc.stdin?.write(text4);
45
+ proc.stdin?.end();
46
+ proc.on("close", (code) => {
47
+ if (code === 0) {
48
+ resolve();
49
+ } else {
50
+ if (platform === "linux") {
51
+ const proc2 = spawn("xsel", [
52
+ "--clipboard",
53
+ "--input"
54
+ ]);
55
+ proc2.stdin?.write(text4);
56
+ proc2.stdin?.end();
57
+ proc2.on("close", (code2) => {
58
+ if (code2 === 0) {
59
+ resolve();
60
+ } else {
61
+ reject(new Error("Failed to copy to clipboard"));
62
+ }
63
+ });
64
+ proc2.on("error", reject);
65
+ } else {
66
+ reject(new Error("Failed to copy to clipboard"));
67
+ }
68
+ }
69
+ });
70
+ proc.on("error", reject);
71
+ });
72
+ },
73
+ catch: (error) => new Error(`Failed to copy to clipboard: ${error}`)
74
+ });
75
+ var openBrowser = (url) => Effect.tryPromise({
76
+ try: () => {
77
+ return new Promise((resolve, reject) => {
78
+ const platform = process.platform;
79
+ let command;
80
+ let args;
81
+ if (platform === "darwin") {
82
+ command = "open";
83
+ args = [
84
+ url
85
+ ];
86
+ } else if (platform === "win32") {
87
+ command = "start";
88
+ args = [
89
+ url
90
+ ];
91
+ } else {
92
+ command = "xdg-open";
93
+ args = [
94
+ url
95
+ ];
96
+ }
97
+ const proc = spawn(command, args);
98
+ proc.on("close", (code) => {
99
+ if (code === 0) {
100
+ resolve();
101
+ } else {
102
+ reject(new Error("Failed to open browser"));
103
+ }
104
+ });
105
+ proc.on("error", reject);
106
+ });
107
+ },
108
+ catch: (error) => new Error(`Failed to open browser: ${error}`)
109
+ });
110
+
111
+ // src/oauth/server.ts
112
+ var OAUTH_TIMEOUT_MS = 5 * 60 * 1e3;
113
+ var getRelayPageHtml = (authUrl) => `
114
+ <!DOCTYPE html>
115
+ <html>
116
+ <head>
117
+ <meta charset="UTF-8">
118
+ <script>
119
+ window.location.href = '${authUrl.replace(/'/g, "\\'")}';
120
+ </script>
121
+ </head>
122
+ <body></body>
123
+ </html>
124
+ `;
125
+ var startOAuthCallbackServer = (callbackPath) => Effect2.gen(function* () {
126
+ const port = yield* Effect2.promise(() => getPort({
127
+ random: true
128
+ }));
129
+ const origin = `http://localhost:${port}`;
130
+ const received = yield* Ref.make(false);
131
+ const outcome = yield* Ref.make(Option.none());
132
+ const parseUrl = (rawUrl) => new URL(rawUrl.startsWith("http") ? rawUrl : `http://localhost${rawUrl}`);
133
+ const router = HttpRouter.empty.pipe(HttpRouter.get("/oauth-relay", Effect2.gen(function* () {
134
+ const request = yield* HttpServerRequest.HttpServerRequest;
135
+ const authUrl = parseUrl(request.url).searchParams.get("authUrl");
136
+ if (!authUrl) {
137
+ return yield* HttpServerResponse.text("Missing authUrl parameter", {
138
+ status: 400
139
+ });
140
+ }
141
+ return yield* HttpServerResponse.text(getRelayPageHtml(authUrl), {
142
+ headers: {
143
+ "Content-Type": "text/html"
144
+ }
145
+ });
146
+ })), HttpRouter.get(callbackPath, Effect2.gen(function* () {
147
+ if (Option.isSome(yield* Ref.get(outcome))) {
148
+ return yield* HttpServerResponse.text("Already received.", {
149
+ status: 400
150
+ });
151
+ }
152
+ const request = yield* HttpServerRequest.HttpServerRequest;
153
+ const params = parseUrl(request.url).searchParams;
154
+ const error = params.get("error");
155
+ if (error) {
156
+ yield* Ref.set(outcome, Option.some({
157
+ success: false,
158
+ reason: error
159
+ }));
160
+ yield* Ref.set(received, true);
161
+ return yield* HttpServerResponse.text(`<html><body><h1>Authentication failed</h1><p>${error}</p></body></html>`, {
162
+ status: 400,
163
+ headers: {
164
+ "Content-Type": "text/html"
165
+ }
166
+ });
167
+ }
168
+ const captured = {};
169
+ for (const [key, value] of params.entries()) {
170
+ captured[key] = value;
171
+ }
172
+ yield* Ref.set(outcome, Option.some({
173
+ success: true,
174
+ params: captured
175
+ }));
176
+ yield* Ref.set(received, true);
177
+ return yield* HttpServerResponse.text("<html><body><h1>Authentication successful! You can close this window.</h1></body></html>", {
178
+ headers: {
179
+ "Content-Type": "text/html"
180
+ }
181
+ });
182
+ })));
183
+ const app = router.pipe(HttpServer.serve());
184
+ const serverLayer = app.pipe(Layer.provide(BunHttpServer.layer({
185
+ port
186
+ })));
187
+ const scope = yield* Scope.make();
188
+ yield* Layer.build(serverLayer).pipe(Scope.extend(scope));
189
+ const waitForResult = (timeoutMs = OAUTH_TIMEOUT_MS) => Effect2.race(Effect2.gen(function* () {
190
+ while (true) {
191
+ if (yield* Ref.get(received)) {
192
+ break;
193
+ }
194
+ yield* Effect2.sleep("500 millis");
195
+ }
196
+ const result = yield* Ref.get(outcome);
197
+ return yield* Option.match(result, {
198
+ onNone: () => Effect2.fail(new Error("OAuth callback received but no result")),
199
+ onSome: (value) => value.success ? Effect2.succeed(value.params) : Effect2.fail(new Error(`OAuth flow failed: ${value.reason}`))
200
+ });
201
+ }), Effect2.sleep(`${timeoutMs} millis`).pipe(Effect2.flatMap(() => Effect2.fail(new Error("OAuth flow timed out")))));
202
+ return {
203
+ port,
204
+ origin,
205
+ open: (authUrl) => openBrowser(`${origin}/oauth-relay?authUrl=${encodeURIComponent(authUrl)}`),
206
+ waitForResult,
207
+ stop: () => Scope.close(scope, Exit.void).pipe(Effect2.catchAll(() => Effect2.void))
208
+ };
209
+ });
210
+
211
+ // src/oauth/recovery.ts
212
+ import * as Effect3 from "effect/Effect";
213
+ import { EntityId, SpaceId } from "@dxos/keys";
214
+ var RECOVERY_CALLBACK_PATH = "/redirect/oauth-recovery";
215
+ var performRecoveryOAuthFlow = Effect3.fn(function* (params) {
216
+ const server = yield* startOAuthCallbackServer(RECOVERY_CALLBACK_PATH);
217
+ return yield* Effect3.gen(function* () {
218
+ const initiateUrl = new URL("/oauth/initiate", params.edgeBaseUrl).toString();
219
+ const response = yield* Effect3.tryPromise({
220
+ try: () => fetch(initiateUrl, {
221
+ method: "POST",
222
+ headers: {
223
+ "Content-Type": "application/json",
224
+ Origin: server.origin
225
+ },
226
+ body: JSON.stringify({
227
+ provider: params.provider,
228
+ scopes: params.scopes,
229
+ spaceId: SpaceId.random(),
230
+ accessTokenId: EntityId.random(),
231
+ purpose: "recovery",
232
+ loginHint: params.loginHint
233
+ })
234
+ }),
235
+ catch: (error) => new Error(`OAuth initiate request failed: ${error instanceof Error ? error.message : String(error)}`)
236
+ });
237
+ const envelope = yield* Effect3.tryPromise({
238
+ try: () => response.json(),
239
+ catch: (error) => new Error(`OAuth initiate response parse failed: ${String(error)}`)
240
+ });
241
+ if (!envelope.success || !envelope.data?.authUrl) {
242
+ return yield* Effect3.fail(new Error(`OAuth initiation failed: ${envelope.error?.message ?? "unknown error"}`));
243
+ }
244
+ yield* server.open(envelope.data.authUrl);
245
+ const callbackParams = yield* server.waitForResult(OAUTH_TIMEOUT_MS);
246
+ const recoveryProof = callbackParams.recoveryProof;
247
+ if (!recoveryProof) {
248
+ return yield* Effect3.fail(new Error("OAuth recovery completed but no recoveryProof was returned."));
249
+ }
250
+ return {
251
+ recoveryProof
252
+ };
253
+ }).pipe(Effect3.ensuring(server.stop()));
254
+ });
255
+
7
256
  // src/util/form-builder.ts
8
257
  var form_builder_exports = {};
9
258
  __export(form_builder_exports, {
10
- build: () => build,
259
+ build: () => build2,
11
260
  each: () => each,
12
- make: () => make,
261
+ make: () => make3,
13
262
  nest: () => nest,
14
263
  nestedOption: () => nestedOption,
15
264
  option: () => option,
16
- set: () => set,
265
+ set: () => set2,
17
266
  when: () => when
18
267
  });
19
268
  import * as Ansi from "@effect/printer-ansi/Ansi";
20
269
  import * as Doc from "@effect/printer/Doc";
21
- import * as Option from "effect/Option";
270
+ import * as Option2 from "effect/Option";
22
271
  import * as Pipeable from "effect/Pipeable";
23
272
  var FormBuilderImpl = class {
24
273
  entries = [];
@@ -32,7 +281,7 @@ var FormBuilderImpl = class {
32
281
  return Pipeable.pipeArguments(this, arguments);
33
282
  }
34
283
  };
35
- var make = (props) => new FormBuilderImpl(props);
284
+ var make3 = (props) => new FormBuilderImpl(props);
36
285
  var calculateDimensions = (entries, prefix) => {
37
286
  const maxKeyLen = Math.max(0, ...entries.map((entry) => entry.key.length));
38
287
  const targetWidth = prefix.length + maxKeyLen + 2;
@@ -64,7 +313,7 @@ var setImpl = (builder, key, value, color) => {
64
313
  }
65
314
  return builder;
66
315
  };
67
- function set(builderOrKey, keyOrValue, valueOrColor, color) {
316
+ function set2(builderOrKey, keyOrValue, valueOrColor, color) {
68
317
  if (builderOrKey instanceof FormBuilderImpl) {
69
318
  const builder = builderOrKey;
70
319
  const key = keyOrValue;
@@ -83,7 +332,7 @@ var nestImpl = (parent, key, builder) => {
83
332
  title: void 0,
84
333
  entries: builder.entries
85
334
  };
86
- let valueDoc = build(nestedBuilder);
335
+ let valueDoc = build2(nestedBuilder);
87
336
  valueDoc = Doc.indent(valueDoc, 2);
88
337
  parent.entries.push({
89
338
  key,
@@ -104,7 +353,7 @@ function nest(parentOrKey, keyOrBuilder, builder) {
104
353
  }
105
354
  }
106
355
  var optionImpl = (builder, key, value, color) => {
107
- if (Option.isSome(value)) {
356
+ if (Option2.isSome(value)) {
108
357
  return setImpl(builder, key, value.value, color);
109
358
  }
110
359
  return builder;
@@ -123,7 +372,7 @@ function option(builderOrKey, keyOrValue, valueOrColor, color) {
123
372
  }
124
373
  }
125
374
  var nestedOptionImpl = (builder, key, value) => {
126
- if (Option.isSome(value)) {
375
+ if (Option2.isSome(value)) {
127
376
  return nestImpl(builder, key, value.value);
128
377
  }
129
378
  return builder;
@@ -161,22 +410,22 @@ function when(builderOrCondition, conditionOrOp, ...ops) {
161
410
  return (builder) => whenImpl(builder, condition, ...allOps);
162
411
  }
163
412
  }
164
- var eachImpl = (builder, items, fn3) => {
165
- items.forEach((item) => fn3(item)(builder));
413
+ var eachImpl = (builder, items, fn4) => {
414
+ items.forEach((item) => fn4(item)(builder));
166
415
  return builder;
167
416
  };
168
- function each(builderOrItems, itemsOrFn, fn3) {
417
+ function each(builderOrItems, itemsOrFn, fn4) {
169
418
  if (builderOrItems instanceof FormBuilderImpl) {
170
419
  const builder = builderOrItems;
171
420
  const items = itemsOrFn;
172
- return eachImpl(builder, items, fn3);
421
+ return eachImpl(builder, items, fn4);
173
422
  } else {
174
423
  const items = builderOrItems;
175
- const fn4 = itemsOrFn;
176
- return (builder) => eachImpl(builder, items, fn4);
424
+ const fn5 = itemsOrFn;
425
+ return (builder) => eachImpl(builder, items, fn5);
177
426
  }
178
427
  }
179
- var build = (builder) => {
428
+ var build2 = (builder) => {
180
429
  const { targetWidth } = calculateDimensions(builder.entries, builder.prefix);
181
430
  const entryLines = [];
182
431
  builder.entries.forEach(({ key, value, isNested }) => {
@@ -212,96 +461,6 @@ var Common = {
212
461
  spaceId: Options.text("space-id").pipe(Options.withSchema(Key.SpaceId), Options.withDescription("Space ID."))
213
462
  };
214
463
 
215
- // src/util/platform.ts
216
- import * as Effect from "effect/Effect";
217
- import { spawn } from "node:child_process";
218
- var copyToClipboard = (text3) => Effect.tryPromise({
219
- try: () => {
220
- return new Promise((resolve, reject) => {
221
- const platform = process.platform;
222
- let command;
223
- let args;
224
- if (platform === "darwin") {
225
- command = "pbcopy";
226
- args = [];
227
- } else if (platform === "win32") {
228
- command = "clip";
229
- args = [];
230
- } else {
231
- command = "xclip";
232
- args = [
233
- "-selection",
234
- "clipboard"
235
- ];
236
- }
237
- const proc = spawn(command, args);
238
- proc.stdin?.write(text3);
239
- proc.stdin?.end();
240
- proc.on("close", (code) => {
241
- if (code === 0) {
242
- resolve();
243
- } else {
244
- if (platform === "linux") {
245
- const proc2 = spawn("xsel", [
246
- "--clipboard",
247
- "--input"
248
- ]);
249
- proc2.stdin?.write(text3);
250
- proc2.stdin?.end();
251
- proc2.on("close", (code2) => {
252
- if (code2 === 0) {
253
- resolve();
254
- } else {
255
- reject(new Error("Failed to copy to clipboard"));
256
- }
257
- });
258
- proc2.on("error", reject);
259
- } else {
260
- reject(new Error("Failed to copy to clipboard"));
261
- }
262
- }
263
- });
264
- proc.on("error", reject);
265
- });
266
- },
267
- catch: (error) => new Error(`Failed to copy to clipboard: ${error}`)
268
- });
269
- var openBrowser = (url) => Effect.tryPromise({
270
- try: () => {
271
- return new Promise((resolve, reject) => {
272
- const platform = process.platform;
273
- let command;
274
- let args;
275
- if (platform === "darwin") {
276
- command = "open";
277
- args = [
278
- url
279
- ];
280
- } else if (platform === "win32") {
281
- command = "start";
282
- args = [
283
- url
284
- ];
285
- } else {
286
- command = "xdg-open";
287
- args = [
288
- url
289
- ];
290
- }
291
- const proc = spawn(command, args);
292
- proc.on("close", (code) => {
293
- if (code === 0) {
294
- resolve();
295
- } else {
296
- reject(new Error("Failed to open browser"));
297
- }
298
- });
299
- proc.on("error", reject);
300
- });
301
- },
302
- catch: (error) => new Error(`Failed to open browser: ${error}`)
303
- });
304
-
305
464
  // src/util/printer.ts
306
465
  import * as AnsiDoc from "@effect/printer-ansi/AnsiDoc";
307
466
  import * as Doc2 from "@effect/printer/Doc";
@@ -313,19 +472,19 @@ var printList = (items) => AnsiDoc.render(Doc2.vsep(items.map((item) => Doc2.cat
313
472
  });
314
473
 
315
474
  // src/util/runtime.ts
316
- import * as Effect2 from "effect/Effect";
475
+ import * as Effect4 from "effect/Effect";
317
476
  import { ClientService } from "@dxos/client";
318
- var withTypes = (...types) => Effect2.gen(function* () {
477
+ var withTypes = (...types) => Effect4.gen(function* () {
319
478
  const client = yield* ClientService;
320
- yield* Effect2.promise(() => client.addTypes(types));
479
+ yield* Effect4.promise(() => client.addTypes(types));
321
480
  });
322
481
 
323
482
  // src/util/space.ts
324
483
  import * as Console from "effect/Console";
325
- import * as Effect3 from "effect/Effect";
326
- import * as Layer from "effect/Layer";
327
- import * as Option2 from "effect/Option";
328
- import { getPersonalSpace } from "@dxos/app-toolkit";
484
+ import * as Effect5 from "effect/Effect";
485
+ import * as Layer2 from "effect/Layer";
486
+ import * as Option3 from "effect/Option";
487
+ import { AppSpace } from "@dxos/app-toolkit";
329
488
  import { ClientService as ClientService2 } from "@dxos/client";
330
489
  import { Database, Feed } from "@dxos/echo";
331
490
  import { createFeedServiceLayer } from "@dxos/echo-client";
@@ -334,14 +493,14 @@ import { log as log2 } from "@dxos/log";
334
493
  import { EdgeReplicationSetting } from "@dxos/protocols/proto/dxos/echo/metadata";
335
494
  import { isBun } from "@dxos/util";
336
495
  var __dxlog_file = "/__w/dxos/dxos/packages/devtools/cli-util/src/util/space.ts";
337
- var getSpace = (spaceId) => Effect3.gen(function* () {
496
+ var getSpace = (spaceId) => Effect5.gen(function* () {
338
497
  const client = yield* ClientService2;
339
- return yield* Option2.fromNullable(client.spaces.get(spaceId));
340
- }).pipe(Effect3.catchTag("NoSuchElementException", () => Effect3.fail(new SpaceNotFoundError(spaceId))));
341
- var spaceIdWithDefault = (spaceId) => Effect3.gen(function* () {
498
+ return yield* Option3.fromNullable(client.spaces.get(spaceId));
499
+ }).pipe(Effect5.catchTag("NoSuchElementException", () => Effect5.fail(new SpaceNotFoundError(spaceId))));
500
+ var spaceIdWithDefault = (spaceId) => Effect5.gen(function* () {
342
501
  const client = yield* ClientService2;
343
- return Option2.getOrElse(spaceId, () => {
344
- const personal = getPersonalSpace(client);
502
+ return Option3.getOrElse(spaceId, () => {
503
+ const personal = AppSpace.getPersonalSpace(client);
345
504
  if (!personal) {
346
505
  throw new Error("No space ID provided and no personal space found.");
347
506
  }
@@ -349,17 +508,17 @@ var spaceIdWithDefault = (spaceId) => Effect3.gen(function* () {
349
508
  });
350
509
  });
351
510
  var spaceLayer = (spaceId$, fallbackToPersonalSpace = false) => {
352
- const getSpace2 = Effect3.fn(function* () {
511
+ const getSpace2 = Effect5.fn(function* () {
353
512
  const client = yield* ClientService2;
354
513
  const resolveSpace = () => {
355
514
  if (!fallbackToPersonalSpace) {
356
- return spaceId$.pipe(Option2.flatMap((id) => Option2.fromNullable(client.spaces.get(id))));
515
+ return spaceId$.pipe(Option3.flatMap((id) => Option3.fromNullable(client.spaces.get(id))));
357
516
  }
358
- return spaceId$.pipe(Option2.flatMap((id) => Option2.fromNullable(client.spaces.get(id))), Option2.orElse(() => Option2.fromNullable(getPersonalSpace(client))), Option2.orElse(() => Option2.fromNullable(client.spaces.get()[0])));
517
+ return spaceId$.pipe(Option3.flatMap((id) => Option3.fromNullable(client.spaces.get(id))), Option3.orElse(() => Option3.fromNullable(AppSpace.getPersonalSpace(client))), Option3.orElse(() => Option3.fromNullable(client.spaces.get()[0])));
359
518
  };
360
- const space = resolveSpace().pipe(Option2.getOrUndefined);
519
+ const space = resolveSpace().pipe(Option3.getOrUndefined);
361
520
  if (space) {
362
- yield* Effect3.promise(() => space.waitUntilReady());
521
+ yield* Effect5.promise(() => space.waitUntilReady());
363
522
  }
364
523
  return space;
365
524
  });
@@ -368,7 +527,7 @@ var spaceLayer = (spaceId$, fallbackToPersonalSpace = false) => {
368
527
  throw new Error("Space not found");
369
528
  }
370
529
  };
371
- const db = Layer.scoped(Database.Service, Effect3.acquireRelease(Effect3.gen(function* () {
530
+ const db = Layer2.scoped(Database.Service, Effect5.acquireRelease(Effect5.gen(function* () {
372
531
  const space = yield* getSpace2();
373
532
  if (!space) {
374
533
  return NO_DB_STUB;
@@ -376,32 +535,32 @@ var spaceLayer = (spaceId$, fallbackToPersonalSpace = false) => {
376
535
  return {
377
536
  db: space.db
378
537
  };
379
- }), (holder) => holder === NO_DB_STUB ? Effect3.void : Effect3.promise(() => holder.db.flush())));
380
- const feed = Layer.unwrapEffect(Effect3.gen(function* () {
538
+ }), (holder) => holder === NO_DB_STUB ? Effect5.void : Effect5.promise(() => holder.db.flush())));
539
+ const feed = Layer2.unwrapEffect(Effect5.gen(function* () {
381
540
  const space = yield* getSpace2();
382
541
  if (!space) {
383
542
  return Feed.notAvailable;
384
543
  }
385
- return createFeedServiceLayer(space.queues);
544
+ return createFeedServiceLayer(space.internal.db);
386
545
  }));
387
- return Layer.merge(db, feed);
546
+ return Layer2.merge(db, feed);
388
547
  };
389
- var waitForSync = Effect3.fn(function* (space) {
548
+ var waitForSync = Effect5.fn(function* (space) {
390
549
  if (!isBun()) {
391
550
  return;
392
551
  }
393
552
  if (space.internal.data.edgeReplication !== EdgeReplicationSetting.ENABLED) {
394
553
  yield* Console.log("Edge replication is disabled, enabling...");
395
- yield* Effect3.promise(() => space.internal.setEdgeReplicationPreference(EdgeReplicationSetting.ENABLED));
554
+ yield* Effect5.promise(() => space.internal.setEdgeReplicationPreference(EdgeReplicationSetting.ENABLED));
396
555
  }
397
- yield* Effect3.promise(() => space.internal.syncToEdge({
556
+ yield* Effect5.promise(() => space.internal.syncToEdge({
398
557
  onProgress: (state) => log2.info("syncing", {
399
558
  state: state ?? "no connection to edge"
400
559
  }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 94, S: this })
401
560
  }));
402
561
  yield* Console.log("Sync complete");
403
562
  });
404
- var flushAndSync = Effect3.fn(function* (opts) {
563
+ var flushAndSync = Effect5.fn(function* (opts) {
405
564
  yield* Database.flush(opts);
406
565
  const spaceId = yield* Database.spaceId;
407
566
  const space = yield* getSpace(spaceId);
@@ -420,7 +579,7 @@ var SpaceNotFoundError = class extends BaseError.extend("SpaceNotFoundError", "S
420
579
 
421
580
  // src/util/space-format.ts
422
581
  import * as Duration from "effect/Duration";
423
- import * as Effect4 from "effect/Effect";
582
+ import * as Effect6 from "effect/Effect";
424
583
  import { SpaceState } from "@dxos/client/echo";
425
584
  var DEFAULT_OPTIONS = {
426
585
  verbose: false,
@@ -428,10 +587,10 @@ var DEFAULT_OPTIONS = {
428
587
  waitSeconds: 0
429
588
  };
430
589
  var READ_TIMEOUT_SECONDS = 2;
431
- var tryWithFallback = (label, run, fallback) => Effect4.tryPromise(run).pipe(Effect4.timeoutFail({
590
+ var tryWithFallback = (label, run, fallback) => Effect6.tryPromise(run).pipe(Effect6.timeoutFail({
432
591
  duration: Duration.seconds(READ_TIMEOUT_SECONDS),
433
592
  onTimeout: () => new Error(`${label} timed out`)
434
- }), Effect4.catchAll(() => Effect4.succeed(fallback)));
593
+ }), Effect6.catchAll(() => Effect6.succeed(fallback)));
435
594
  var tryWithFallbackSync = (read, fallback) => {
436
595
  try {
437
596
  return read();
@@ -439,16 +598,16 @@ var tryWithFallbackSync = (read, fallback) => {
439
598
  return fallback;
440
599
  }
441
600
  };
442
- var formatSpace = Effect4.fn(function* (space, options = {}) {
601
+ var formatSpace = Effect6.fn(function* (space, options = {}) {
443
602
  const { waitSeconds } = {
444
603
  ...DEFAULT_OPTIONS,
445
604
  ...options
446
605
  };
447
606
  if (waitSeconds > 0) {
448
- yield* Effect4.tryPromise(() => space.waitUntilReady()).pipe(Effect4.timeoutFail({
607
+ yield* Effect6.tryPromise(() => space.waitUntilReady()).pipe(Effect6.timeoutFail({
449
608
  duration: Duration.seconds(waitSeconds),
450
609
  onTimeout: () => new Error("waitUntilReady timed out")
451
- }), Effect4.catchAll(() => Effect4.void));
610
+ }), Effect6.catchAll(() => Effect6.void));
452
611
  }
453
612
  const state = tryWithFallbackSync(() => space.state.get(), SpaceState.SPACE_INITIALIZING);
454
613
  const ready = state === SpaceState.SPACE_READY;
@@ -505,35 +664,38 @@ var getSyncIndicator = (up, down) => {
505
664
  }
506
665
  }
507
666
  };
508
- var printSpace = (spaceData) => make({
667
+ var printSpace = (spaceData) => make3({
509
668
  title: spaceData.name ?? spaceData.id
510
- }).pipe(set("id", spaceData.id), set("state", spaceData.state), set("key", spaceData.key), set("members", spaceData.members), set("objects", spaceData.objects), set("epoch", spaceData.epoch ?? "<none>"), set("startup", spaceData.startup ? `${spaceData.startup}ms` : "<none>"), set("syncState", spaceData.syncState), set("automergeRoot", spaceData.automergeRoot ?? "<none>"), build);
669
+ }).pipe(set2("id", spaceData.id), set2("state", spaceData.state), set2("key", spaceData.key), set2("members", spaceData.members), set2("objects", spaceData.objects), set2("epoch", spaceData.epoch ?? "<none>"), set2("startup", spaceData.startup ? `${spaceData.startup}ms` : "<none>"), set2("syncState", spaceData.syncState), set2("automergeRoot", spaceData.automergeRoot ?? "<none>"), build2);
511
670
 
512
671
  // src/util/timeout.ts
513
672
  import * as Config from "effect/Config";
514
673
  import * as Duration2 from "effect/Duration";
515
- import * as Effect5 from "effect/Effect";
516
- import * as Option3 from "effect/Option";
517
- var withTimeout = Effect5.fnUntraced(function* (effect) {
674
+ import * as Effect7 from "effect/Effect";
675
+ import * as Option4 from "effect/Option";
676
+ var withTimeout = Effect7.fnUntraced(function* (effect) {
518
677
  const timeout2 = yield* Config.integer("TIMEOUT").pipe(Config.option);
519
- const duration = timeout2.pipe(Option3.map(Duration2.millis), Option3.getOrElse(() => Duration2.infinity));
520
- return yield* effect.pipe(Effect5.timeout(duration));
678
+ const duration = timeout2.pipe(Option4.map(Duration2.millis), Option4.getOrElse(() => Duration2.infinity));
679
+ return yield* effect.pipe(Effect7.timeout(duration));
521
680
  });
522
681
  export {
523
682
  CommandConfig,
524
683
  Common,
525
684
  form_builder_exports as FormBuilder,
685
+ OAUTH_TIMEOUT_MS,
526
686
  SpaceNotFoundError,
527
687
  copyToClipboard,
528
688
  flushAndSync,
529
689
  formatSpace,
530
690
  getSpace,
531
691
  openBrowser,
692
+ performRecoveryOAuthFlow,
532
693
  print,
533
694
  printList,
534
695
  printSpace,
535
696
  spaceIdWithDefault,
536
697
  spaceLayer,
698
+ startOAuthCallbackServer,
537
699
  waitForSync,
538
700
  withTimeout,
539
701
  withTypes