@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.
- package/dist/lib/node-esm/index.mjs +308 -154
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/oauth/index.d.ts +3 -0
- package/dist/types/src/oauth/index.d.ts.map +1 -0
- package/dist/types/src/oauth/recovery.d.ts +26 -0
- package/dist/types/src/oauth/recovery.d.ts.map +1 -0
- package/dist/types/src/oauth/server.d.ts +28 -0
- package/dist/types/src/oauth/server.d.ts.map +1 -0
- package/dist/types/src/util/space.d.ts +2 -2
- package/dist/types/src/util/space.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +20 -16
- package/src/index.ts +1 -0
- package/src/oauth/index.ts +6 -0
- package/src/oauth/recovery.ts +76 -0
- package/src/oauth/server.ts +157 -0
- package/src/util/space.ts +6 -17
|
@@ -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: () =>
|
|
259
|
+
build: () => build2,
|
|
11
260
|
each: () => each,
|
|
12
|
-
make: () =>
|
|
261
|
+
make: () => make3,
|
|
13
262
|
nest: () => nest,
|
|
14
263
|
nestedOption: () => nestedOption,
|
|
15
264
|
option: () => option,
|
|
16
|
-
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
|
|
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
|
|
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
|
|
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 =
|
|
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 (
|
|
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 (
|
|
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,
|
|
165
|
-
items.forEach((item) =>
|
|
413
|
+
var eachImpl = (builder, items, fn4) => {
|
|
414
|
+
items.forEach((item) => fn4(item)(builder));
|
|
166
415
|
return builder;
|
|
167
416
|
};
|
|
168
|
-
function each(builderOrItems, itemsOrFn,
|
|
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,
|
|
421
|
+
return eachImpl(builder, items, fn4);
|
|
173
422
|
} else {
|
|
174
423
|
const items = builderOrItems;
|
|
175
|
-
const
|
|
176
|
-
return (builder) => eachImpl(builder, items,
|
|
424
|
+
const fn5 = itemsOrFn;
|
|
425
|
+
return (builder) => eachImpl(builder, items, fn5);
|
|
177
426
|
}
|
|
178
427
|
}
|
|
179
|
-
var
|
|
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
|
|
475
|
+
import * as Effect4 from "effect/Effect";
|
|
317
476
|
import { ClientService } from "@dxos/client";
|
|
318
|
-
var withTypes = (...types) =>
|
|
477
|
+
var withTypes = (...types) => Effect4.gen(function* () {
|
|
319
478
|
const client = yield* ClientService;
|
|
320
|
-
yield*
|
|
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
|
|
326
|
-
import * as
|
|
327
|
-
import * as
|
|
328
|
-
import {
|
|
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
|
|
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) =>
|
|
495
|
+
var getSpace = (spaceId) => Effect5.gen(function* () {
|
|
338
496
|
const client = yield* ClientService2;
|
|
339
|
-
return yield*
|
|
340
|
-
}).pipe(
|
|
341
|
-
var spaceIdWithDefault = (spaceId) =>
|
|
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
|
|
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 =
|
|
510
|
+
const getSpace2 = Effect5.fn(function* () {
|
|
353
511
|
const client = yield* ClientService2;
|
|
354
512
|
const resolveSpace = () => {
|
|
355
513
|
if (!fallbackToPersonalSpace) {
|
|
356
|
-
return spaceId$.pipe(
|
|
514
|
+
return spaceId$.pipe(Option3.flatMap((id) => Option3.fromNullable(client.spaces.get(id))));
|
|
357
515
|
}
|
|
358
|
-
return spaceId$.pipe(
|
|
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(
|
|
518
|
+
const space = resolveSpace().pipe(Option3.getOrUndefined);
|
|
361
519
|
if (space) {
|
|
362
|
-
yield*
|
|
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 =
|
|
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 ?
|
|
380
|
-
|
|
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 =
|
|
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*
|
|
546
|
+
yield* Effect5.promise(() => space.internal.setEdgeReplicationPreference(EdgeReplicationSetting.ENABLED));
|
|
396
547
|
}
|
|
397
|
-
yield*
|
|
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:
|
|
551
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 86, S: this })
|
|
401
552
|
}));
|
|
402
553
|
yield* Console.log("Sync complete");
|
|
403
554
|
});
|
|
404
|
-
var flushAndSync =
|
|
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
|
|
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) =>
|
|
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
|
-
}),
|
|
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 =
|
|
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*
|
|
599
|
+
yield* Effect6.tryPromise(() => space.waitUntilReady()).pipe(Effect6.timeoutFail({
|
|
449
600
|
duration: Duration.seconds(waitSeconds),
|
|
450
601
|
onTimeout: () => new Error("waitUntilReady timed out")
|
|
451
|
-
}),
|
|
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) =>
|
|
659
|
+
var printSpace = (spaceData) => make3({
|
|
509
660
|
title: spaceData.name ?? spaceData.id
|
|
510
|
-
}).pipe(
|
|
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
|
|
516
|
-
import * as
|
|
517
|
-
var withTimeout =
|
|
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(
|
|
520
|
-
return yield* effect.pipe(
|
|
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
|