@dxos/cli-util 0.9.0 → 0.9.1-staging.ee54ba693a

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,35 +472,34 @@ 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
- import { Database, Feed } from "@dxos/echo";
331
- import { createFeedServiceLayer } from "@dxos/echo-client";
489
+ import { Database } from "@dxos/echo";
332
490
  import { BaseError } from "@dxos/errors";
333
491
  import { log as log2 } from "@dxos/log";
334
492
  import { EdgeReplicationSetting } from "@dxos/protocols/proto/dxos/echo/metadata";
335
493
  import { isBun } from "@dxos/util";
336
494
  var __dxlog_file = "/__w/dxos/dxos/packages/devtools/cli-util/src/util/space.ts";
337
- var getSpace = (spaceId) => Effect3.gen(function* () {
495
+ var getSpace = (spaceId) => Effect5.gen(function* () {
338
496
  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* () {
497
+ return yield* Option3.fromNullable(client.spaces.get(spaceId));
498
+ }).pipe(Effect5.catchTag("NoSuchElementException", () => Effect5.fail(new SpaceNotFoundError(spaceId))));
499
+ var spaceIdWithDefault = (spaceId) => Effect5.gen(function* () {
342
500
  const client = yield* ClientService2;
343
- return Option2.getOrElse(spaceId, () => {
344
- const personal = getPersonalSpace(client);
501
+ return Option3.getOrElse(spaceId, () => {
502
+ const personal = AppSpace.getPersonalSpace(client);
345
503
  if (!personal) {
346
504
  throw new Error("No space ID provided and no personal space found.");
347
505
  }
@@ -349,17 +507,17 @@ var spaceIdWithDefault = (spaceId) => Effect3.gen(function* () {
349
507
  });
350
508
  });
351
509
  var spaceLayer = (spaceId$, fallbackToPersonalSpace = false) => {
352
- const getSpace2 = Effect3.fn(function* () {
510
+ const getSpace2 = Effect5.fn(function* () {
353
511
  const client = yield* ClientService2;
354
512
  const resolveSpace = () => {
355
513
  if (!fallbackToPersonalSpace) {
356
- return spaceId$.pipe(Option2.flatMap((id) => Option2.fromNullable(client.spaces.get(id))));
514
+ return spaceId$.pipe(Option3.flatMap((id) => Option3.fromNullable(client.spaces.get(id))));
357
515
  }
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])));
516
+ 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
517
  };
360
- const space = resolveSpace().pipe(Option2.getOrUndefined);
518
+ const space = resolveSpace().pipe(Option3.getOrUndefined);
361
519
  if (space) {
362
- yield* Effect3.promise(() => space.waitUntilReady());
520
+ yield* Effect5.promise(() => space.waitUntilReady());
363
521
  }
364
522
  return space;
365
523
  });
@@ -368,7 +526,7 @@ var spaceLayer = (spaceId$, fallbackToPersonalSpace = false) => {
368
526
  throw new Error("Space not found");
369
527
  }
370
528
  };
371
- const db = Layer.scoped(Database.Service, Effect3.acquireRelease(Effect3.gen(function* () {
529
+ const db = Layer2.scoped(Database.Service, Effect5.acquireRelease(Effect5.gen(function* () {
372
530
  const space = yield* getSpace2();
373
531
  if (!space) {
374
532
  return NO_DB_STUB;
@@ -376,32 +534,25 @@ var spaceLayer = (spaceId$, fallbackToPersonalSpace = false) => {
376
534
  return {
377
535
  db: space.db
378
536
  };
379
- }), (holder) => holder === NO_DB_STUB ? Effect3.void : Effect3.promise(() => holder.db.flush())));
380
- const feed = Layer.unwrapEffect(Effect3.gen(function* () {
381
- const space = yield* getSpace2();
382
- if (!space) {
383
- return Feed.notAvailable;
384
- }
385
- return createFeedServiceLayer(space.queues);
386
- }));
387
- return Layer.merge(db, feed);
537
+ }), (holder) => holder === NO_DB_STUB ? Effect5.void : Effect5.promise(() => holder.db.flush())));
538
+ return db;
388
539
  };
389
- var waitForSync = Effect3.fn(function* (space) {
540
+ var waitForSync = Effect5.fn(function* (space) {
390
541
  if (!isBun()) {
391
542
  return;
392
543
  }
393
544
  if (space.internal.data.edgeReplication !== EdgeReplicationSetting.ENABLED) {
394
545
  yield* Console.log("Edge replication is disabled, enabling...");
395
- yield* Effect3.promise(() => space.internal.setEdgeReplicationPreference(EdgeReplicationSetting.ENABLED));
546
+ yield* Effect5.promise(() => space.internal.setEdgeReplicationPreference(EdgeReplicationSetting.ENABLED));
396
547
  }
397
- yield* Effect3.promise(() => space.internal.syncToEdge({
548
+ yield* Effect5.promise(() => space.internal.syncToEdge({
398
549
  onProgress: (state) => log2.info("syncing", {
399
550
  state: state ?? "no connection to edge"
400
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 94, S: this })
551
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 86, S: this })
401
552
  }));
402
553
  yield* Console.log("Sync complete");
403
554
  });
404
- var flushAndSync = Effect3.fn(function* (opts) {
555
+ var flushAndSync = Effect5.fn(function* (opts) {
405
556
  yield* Database.flush(opts);
406
557
  const spaceId = yield* Database.spaceId;
407
558
  const space = yield* getSpace(spaceId);
@@ -420,7 +571,7 @@ var SpaceNotFoundError = class extends BaseError.extend("SpaceNotFoundError", "S
420
571
 
421
572
  // src/util/space-format.ts
422
573
  import * as Duration from "effect/Duration";
423
- import * as Effect4 from "effect/Effect";
574
+ import * as Effect6 from "effect/Effect";
424
575
  import { SpaceState } from "@dxos/client/echo";
425
576
  var DEFAULT_OPTIONS = {
426
577
  verbose: false,
@@ -428,10 +579,10 @@ var DEFAULT_OPTIONS = {
428
579
  waitSeconds: 0
429
580
  };
430
581
  var READ_TIMEOUT_SECONDS = 2;
431
- var tryWithFallback = (label, run, fallback) => Effect4.tryPromise(run).pipe(Effect4.timeoutFail({
582
+ var tryWithFallback = (label, run, fallback) => Effect6.tryPromise(run).pipe(Effect6.timeoutFail({
432
583
  duration: Duration.seconds(READ_TIMEOUT_SECONDS),
433
584
  onTimeout: () => new Error(`${label} timed out`)
434
- }), Effect4.catchAll(() => Effect4.succeed(fallback)));
585
+ }), Effect6.catchAll(() => Effect6.succeed(fallback)));
435
586
  var tryWithFallbackSync = (read, fallback) => {
436
587
  try {
437
588
  return read();
@@ -439,16 +590,16 @@ var tryWithFallbackSync = (read, fallback) => {
439
590
  return fallback;
440
591
  }
441
592
  };
442
- var formatSpace = Effect4.fn(function* (space, options = {}) {
593
+ var formatSpace = Effect6.fn(function* (space, options = {}) {
443
594
  const { waitSeconds } = {
444
595
  ...DEFAULT_OPTIONS,
445
596
  ...options
446
597
  };
447
598
  if (waitSeconds > 0) {
448
- yield* Effect4.tryPromise(() => space.waitUntilReady()).pipe(Effect4.timeoutFail({
599
+ yield* Effect6.tryPromise(() => space.waitUntilReady()).pipe(Effect6.timeoutFail({
449
600
  duration: Duration.seconds(waitSeconds),
450
601
  onTimeout: () => new Error("waitUntilReady timed out")
451
- }), Effect4.catchAll(() => Effect4.void));
602
+ }), Effect6.catchAll(() => Effect6.void));
452
603
  }
453
604
  const state = tryWithFallbackSync(() => space.state.get(), SpaceState.SPACE_INITIALIZING);
454
605
  const ready = state === SpaceState.SPACE_READY;
@@ -505,35 +656,38 @@ var getSyncIndicator = (up, down) => {
505
656
  }
506
657
  }
507
658
  };
508
- var printSpace = (spaceData) => make({
659
+ var printSpace = (spaceData) => make3({
509
660
  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);
661
+ }).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
662
 
512
663
  // src/util/timeout.ts
513
664
  import * as Config from "effect/Config";
514
665
  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) {
666
+ import * as Effect7 from "effect/Effect";
667
+ import * as Option4 from "effect/Option";
668
+ var withTimeout = Effect7.fnUntraced(function* (effect) {
518
669
  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));
670
+ const duration = timeout2.pipe(Option4.map(Duration2.millis), Option4.getOrElse(() => Duration2.infinity));
671
+ return yield* effect.pipe(Effect7.timeout(duration));
521
672
  });
522
673
  export {
523
674
  CommandConfig,
524
675
  Common,
525
676
  form_builder_exports as FormBuilder,
677
+ OAUTH_TIMEOUT_MS,
526
678
  SpaceNotFoundError,
527
679
  copyToClipboard,
528
680
  flushAndSync,
529
681
  formatSpace,
530
682
  getSpace,
531
683
  openBrowser,
684
+ performRecoveryOAuthFlow,
532
685
  print,
533
686
  printList,
534
687
  printSpace,
535
688
  spaceIdWithDefault,
536
689
  spaceLayer,
690
+ startOAuthCallbackServer,
537
691
  waitForSync,
538
692
  withTimeout,
539
693
  withTypes